From 9ba8f216fd7856ce5fef06bf82ecb8f8a2e7e630 Mon Sep 17 00:00:00 2001 From: Thomas Steur Date: Fri, 3 Jul 2015 00:54:27 +0000 Subject: generate pages instead of implementing them in each controller --- CHANGELOG.md | 23 + .../ReportTotalsCalculator.php | 4 +- core/API/DataTablePostProcessor.php | 3 +- core/Application/Kernel/EnvironmentValidator.php | 1 - core/Category/Category.php | 100 + core/Category/CategoryList.php | 95 + core/Category/Subcategory.php | 146 + core/DataTable/Filter/PivotByDimension.php | 3 +- core/Http/ControllerResolver.php | 49 +- core/Menu/MenuMain.php | 19 - core/Menu/MenuReporting.php | 143 - core/Period/Day.php | 1 - core/Period/Range.php | 1 - core/Period/Week.php | 1 - core/Plugin.php | 2 +- core/Plugin/Categories.php | 71 + core/Plugin/Controller.php | 61 +- core/Plugin/Menu.php | 12 +- core/Plugin/Report.php | 274 +- core/Plugin/Reports.php | 189 + core/Plugin/ViewDataTable.php | 18 +- core/Plugin/Visualization.php | 7 +- core/Plugin/Widgets.php | 233 +- core/Report/ReportWidgetConfig.php | 92 + core/Report/ReportWidgetFactory.php | 119 + core/Tracker.php | 1 - core/Updates/3.0.0-b1.php | 351 + core/Version.php | 2 +- core/View/ReportsByDimension.php | 129 - core/ViewDataTable/Config.php | 4 +- core/ViewDataTable/Factory.php | 11 +- core/Widget/Widget.php | 37 + core/Widget/WidgetConfig.php | 343 + core/Widget/WidgetContainerConfig.php | 131 + core/Widget/WidgetsList.php | 247 + core/WidgetsList.php | 287 - lang/en.json | 1 + misc/others/iframeWidget_localhost.php | 31 +- plugins/API/API.php | 162 +- plugins/API/ProcessedReport.php | 86 +- plugins/API/Reports/Get.php | 6 +- plugins/API/SegmentMetadata.php | 167 + plugins/API/WidgetMetadata.php | 282 + plugins/API/tests/Unit/WidgetMetadataTest.php | 278 + plugins/Actions/API.php | 3 +- plugins/Actions/Actions.php | 1 + .../Actions/Categories/DownloadsSubcategory.php | 19 + .../Actions/Categories/EntryPagesSubcategory.php | 19 + .../Actions/Categories/ExitPagesSubcategory.php | 19 + plugins/Actions/Categories/OutlinksSubcategory.php | 19 + .../Actions/Categories/PageTitlesSubcategory.php | 19 + plugins/Actions/Categories/PagesSubcategory.php | 19 + .../Actions/Categories/SiteSearchSubcategory.php | 19 + plugins/Actions/Controller.php | 45 - plugins/Actions/Menu.php | 29 - plugins/Actions/Reports/Base.php | 2 +- plugins/Actions/Reports/GetDownloads.php | 3 +- plugins/Actions/Reports/GetEntryPageTitles.php | 12 +- plugins/Actions/Reports/GetEntryPageUrls.php | 8 +- plugins/Actions/Reports/GetExitPageTitles.php | 14 +- plugins/Actions/Reports/GetExitPageUrls.php | 8 +- plugins/Actions/Reports/GetOutlinks.php | 3 +- plugins/Actions/Reports/GetPageTitles.php | 10 +- .../Reports/GetPageTitlesFollowingSiteSearch.php | 6 +- plugins/Actions/Reports/GetPageUrls.php | 11 +- .../Reports/GetPageUrlsFollowingSiteSearch.php | 8 +- .../Actions/Reports/GetSiteSearchCategories.php | 5 +- plugins/Actions/Reports/GetSiteSearchKeywords.php | 2 +- .../Reports/GetSiteSearchNoResultKeywords.php | 5 +- plugins/Actions/Reports/SiteSearchBase.php | 2 +- plugins/Actions/templates/indexSiteSearch.twig | 21 - .../Contents/Categories/ContentsSubcategory.php | 19 + plugins/Contents/Contents.php | 2 +- plugins/Contents/Controller.php | 51 - plugins/Contents/Menu.php | 24 - plugins/Contents/Reports/Base.php | 13 +- plugins/Contents/Reports/GetContentNames.php | 1 - plugins/Contents/Reports/GetContentPieces.php | 2 - plugins/Contents/Widgets/ContentsByDimension.php | 21 + plugins/Contents/tests/System/expected/.gitkeep | 0 ...tentNames_lastN__API.getProcessedReport_day.xml | 1 + ...entPieces_lastN__API.getProcessedReport_day.xml | 1 + plugins/CoreConsole/Commands/GenerateReport.php | 24 +- plugins/CoreConsole/Commands/GenerateWidget.php | 76 +- plugins/CoreHome/Categories/ActionsCategory.php | 17 + plugins/CoreHome/Categories/DevicesSubcategory.php | 19 + .../CoreHome/Categories/EngagementSubcategory.php | 19 + .../CoreHome/Categories/SoftwareSubcategory.php | 19 + plugins/CoreHome/Categories/VisitorsCategory.php | 17 + .../Categories/VisitorsOverviewSubcategory.php | 19 + .../CoreHome/Columns/Metrics/AverageTimeOnSite.php | 2 +- plugins/CoreHome/Controller.php | 35 +- plugins/CoreHome/CoreHome.php | 32 +- plugins/CoreHome/Widgets.php | 63 - plugins/CoreHome/Widgets/GetDonateForm.php | 48 + plugins/CoreHome/Widgets/GetPromoVideo.php | 44 + .../activityindicator.directive.js | 31 + .../activity-indicator/activityindicator.html | 3 + .../angularjs/ajax-form/ajax-form.directive.js | 4 +- .../common/directives/focus-anywhere-but-here.js | 8 +- .../CoreHome/angularjs/common/filters/escape.js | 16 + .../angularjs/common/services/global-ajax-queue.js | 14 + .../angularjs/common/services/piwik-url.js | 54 + .../common/services/report-metadata-model.js | 52 + .../common/services/reporting-pages-model.js | 58 + .../CoreHome/angularjs/history/history.service.js | 21 +- plugins/CoreHome/angularjs/http404check.js | 6 +- .../menudropdown/menudropdown.directive.html | 2 +- .../menudropdown/menudropdown.directive.js | 13 +- .../popover-handler/popover-handler.directive.js | 74 + .../reporting-menu/reportingmenu-model.js | 153 + .../reporting-menu/reportingmenu.controller.js | 125 + .../reporting-menu/reportingmenu.directive.html | 40 + .../reporting-menu/reportingmenu.directive.js | 31 + .../reporting-page/reportingpage-model.js | 196 + .../reporting-page/reportingpage.controller.js | 56 + .../reporting-page/reportingpage.directive.html | 25 + .../reporting-page/reportingpage.directive.js | 31 + .../widget-bydimension-container.directive.html | 25 + .../widget-bydimension-container.directive.js | 67 + .../widgetcontainer.directive.html | 10 + .../widget-container/widgetcontainer.directive.js | 32 + .../widget-loader/widgetloader.directive.html | 13 + .../widget-loader/widgetloader.directive.js | 134 + .../angularjs/widget/widget.directive.html | 23 + .../CoreHome/angularjs/widget/widget.directive.js | 93 + plugins/CoreHome/javascripts/broadcast.js | 67 +- plugins/CoreHome/javascripts/corehome.js | 54 - plugins/CoreHome/javascripts/dataTable.js | 1 + plugins/CoreHome/javascripts/menu.js | 114 - plugins/CoreHome/javascripts/menu_init.js | 19 - plugins/CoreHome/javascripts/sparkline.js | 28 +- plugins/CoreHome/lang/en.json | 3 +- plugins/CoreHome/stylesheets/coreHome.less | 6 + plugins/CoreHome/stylesheets/zen-mode.less | 16 +- .../ReportsByDimension/_reportsByDimension.twig | 29 - plugins/CoreHome/templates/_indexContent.twig | 3 + .../CoreHome/templates/getDefaultIndexView.twig | 5 +- plugins/CoreHome/templates/widgetContainer.twig | 18 + .../JqplotDataGenerator/Evolution.php | 41 +- .../Visualizations/Sparkline.php | 4 +- .../Visualizations/Sparklines.php | 147 + .../Visualizations/Sparklines/Config.php | 354 + .../javascripts/jqplotEvolutionGraph.js | 35 +- .../templates/_dataTableViz_sparklines.twig | 31 + plugins/CoreVisualizations/templates/macros.twig | 32 + .../tests/Integration/SparklinesConfigTest.php | 128 + .../tests/Unit/SparklinesConfigTest.php | 130 + .../Categories/CustomVariablesSubcategory.php | 19 + plugins/CustomVariables/Reports/Base.php | 2 +- .../CustomVariables/Reports/GetCustomVariables.php | 4 +- plugins/DBStats/Reports/GetMetricDataSummary.php | 3 +- .../DBStats/Reports/GetMetricDataSummaryByYear.php | 3 +- plugins/DBStats/Reports/GetReportDataSummary.php | 3 +- .../DBStats/Reports/GetReportDataSummaryByYear.php | 3 +- plugins/Dashboard/API.php | 54 +- plugins/Dashboard/Categories/DashboardCategory.php | 17 + plugins/Dashboard/Controller.php | 17 +- plugins/Dashboard/Dashboard.php | 64 +- plugins/Dashboard/Menu.php | 19 - plugins/Dashboard/Model.php | 8 +- .../angularjs/common/services/dashboards-model.js | 68 + .../angularjs/dashboard/dashboard.directive.js | 103 + plugins/Dashboard/javascripts/dashboard.js | 106 +- plugins/Dashboard/javascripts/dashboardObject.js | 143 +- plugins/Dashboard/javascripts/dashboardWidget.js | 9 +- plugins/Dashboard/javascripts/widgetMenu.js | 102 +- plugins/Dashboard/templates/embeddedIndex.twig | 8 +- plugins/DevicePlugins/Reports/Base.php | 2 +- plugins/DevicePlugins/Reports/GetPlugin.php | 5 +- plugins/DevicesDetection/Controller.php | 41 - plugins/DevicesDetection/Menu.php | 7 - plugins/DevicesDetection/Reports/Base.php | 2 +- plugins/DevicesDetection/Reports/GetBrand.php | 5 +- .../DevicesDetection/Reports/GetBrowserEngines.php | 5 +- .../Reports/GetBrowserVersions.php | 8 +- plugins/DevicesDetection/Reports/GetBrowsers.php | 10 +- plugins/DevicesDetection/Reports/GetModel.php | 3 +- plugins/DevicesDetection/Reports/GetOsFamilies.php | 8 +- plugins/DevicesDetection/Reports/GetOsVersions.php | 8 +- plugins/DevicesDetection/Reports/GetType.php | 3 +- plugins/DevicesDetection/templates/devices.twig | 19 - plugins/DevicesDetection/templates/software.twig | 23 - plugins/Ecommerce/Categories/EcommerceCategory.php | 17 + .../Categories/EcommerceLogSubcategory.php | 19 + .../Categories/EcommerceOverviewSubcategory.php | 19 + .../Ecommerce/Categories/ProductSubcategory.php | 19 + plugins/Ecommerce/Categories/SalesSubcategory.php | 19 + plugins/Ecommerce/Controller.php | 117 +- plugins/Ecommerce/Menu.php | 41 - plugins/Ecommerce/Reports/Base.php | 5 +- plugins/Ecommerce/Reports/BaseItem.php | 45 +- plugins/Ecommerce/Reports/GetItemsCategory.php | 3 +- plugins/Ecommerce/Reports/GetItemsName.php | 3 +- plugins/Ecommerce/Reports/GetItemsSku.php | 3 +- plugins/Ecommerce/Widgets.php | 35 - plugins/Ecommerce/Widgets/GetEcommerceLog.php | 28 + plugins/Ecommerce/Widgets/ProductsByDimension.php | 34 + .../Ecommerce/templates/conversionOverview.twig | 15 + plugins/Ecommerce/templates/ecommerceLog.twig | 3 - plugins/Ecommerce/templates/getSparklines.twig | 55 + plugins/Events/Categories/EventsSubcategory.php | 19 + plugins/Events/Controller.php | 104 - plugins/Events/Events.php | 3 +- plugins/Events/Menu.php | 21 - plugins/Events/Reports/Base.php | 20 +- plugins/Events/Reports/GetAction.php | 1 - plugins/Events/Reports/GetActionFromCategoryId.php | 2 +- plugins/Events/Reports/GetActionFromNameId.php | 2 +- plugins/Events/Reports/GetCategory.php | 1 - plugins/Events/Reports/GetCategoryFromActionId.php | 2 +- plugins/Events/Reports/GetCategoryFromNameId.php | 2 +- plugins/Events/Reports/GetName.php | 1 - plugins/Events/Reports/GetNameFromActionId.php | 2 +- plugins/Events/Reports/GetNameFromCategoryId.php | 2 +- plugins/Events/Widgets/EventsByDimension.php | 22 + plugins/Events/templates/index.twig | 2 - plugins/ExamplePlugin/Menu.php | 13 +- plugins/ExamplePlugin/Widgets.php | 67 - plugins/ExamplePlugin/Widgets/MyExampleWidget.php | 80 + plugins/ExampleReport/Reports/Base.php | 2 +- plugins/ExampleReport/Reports/GetExampleReport.php | 8 +- plugins/ExampleRssWidget/Widgets.php | 63 - plugins/ExampleRssWidget/Widgets/RssChangelog.php | 49 + plugins/ExampleRssWidget/Widgets/RssPiwik.php | 47 + plugins/ExampleUI/API.php | 1 + plugins/ExampleUI/Categories/ExampleUiCategory.php | 17 + plugins/ExampleUI/Controller.php | 154 - plugins/ExampleUI/Menu.php | 25 - plugins/ExampleUI/Reports/Base.php | 19 + plugins/ExampleUI/Reports/GetPlanetRatios.php | 74 + .../ExampleUI/Reports/GetPlanetRatiosWithLogos.php | 44 + plugins/ExampleUI/Reports/GetTemperatures.php | 93 + .../ExampleUI/Reports/GetTemperaturesEvolution.php | 95 + plugins/ExampleUI/lang/en.json | 8 + plugins/ExampleUI/plugin.json | 17 +- plugins/Goals/API.php | 3 +- .../Goals/Categories/AddANewGoalSubcategory.php | 19 + plugins/Goals/Categories/GoalsCategory.php | 17 + .../Goals/Categories/GoalsOverviewSubcategory.php | 19 + .../Goals/Categories/ManageGoalsSubcategory.php | 19 + plugins/Goals/Controller.php | 251 +- plugins/Goals/Conversions.php | 45 + plugins/Goals/Goals.php | 58 +- plugins/Goals/Menu.php | 43 - plugins/Goals/Pages.php | 339 + plugins/Goals/Reports/Base.php | 2 +- plugins/Goals/Reports/Get.php | 111 + plugins/Goals/Widgets.php | 39 - plugins/Goals/Widgets/AddNewGoal.php | 38 + plugins/Goals/Widgets/EditGoals.php | 37 + plugins/Goals/lang/en.json | 5 +- .../Goals/templates/_titleAndEvolutionGraph.twig | 86 - plugins/Goals/templates/addNewGoal.twig | 1 - plugins/Goals/templates/conversionOverview.twig | 15 + plugins/Goals/templates/editGoals.twig | 2 - plugins/Goals/templates/getGoalReportView.twig | 66 - plugins/Goals/templates/getOverviewView.twig | 58 - plugins/Insights/Widgets.php | 20 - plugins/Insights/Widgets/GetInsightsOverview.php | 20 + .../Widgets/GetOverallMoversAndShakers.php | 20 + plugins/Live/Categories/LiveCategory.php | 17 + plugins/Live/Categories/VisitorLogSubcategory.php | 19 + plugins/Live/Reports/Base.php | 2 +- plugins/Live/Reports/GetLastVisitsDetails.php | 24 +- plugins/Live/Reports/GetSimpleLastVisitCount.php | 9 +- plugins/Live/Widgets.php | 27 - plugins/Live/Widgets/GetVisitorProfilePopup.php | 33 + plugins/Live/Widgets/Widget.php | 21 + plugins/Live/templates/index.twig | 2 +- plugins/Morpheus/javascripts/piwikHelper.js | 8 +- plugins/Morpheus/stylesheets/ui/_map.less | 4 + plugins/Morpheus/templates/layout.twig | 2 + .../MultiSites/Categories/MultiSitesCategory.php | 17 + plugins/MultiSites/Reports/Base.php | 2 +- plugins/Provider/Reports/GetProvider.php | 13 +- .../Categories/AllReferrersSubcategory.php | 19 + .../Referrers/Categories/CampaignsSubcategory.php | 19 + plugins/Referrers/Categories/ReferrersCategory.php | 17 + .../Categories/ReferrersOverviewSubcategory.php | 19 + .../Categories/SearchEnginesSubcategory.php | 19 + .../Referrers/Categories/WebsitesSubcategory.php | 19 + plugins/Referrers/Controller.php | 192 +- plugins/Referrers/Menu.php | 23 - plugins/Referrers/Reports/Base.php | 2 +- plugins/Referrers/Reports/GetAll.php | 12 +- plugins/Referrers/Reports/GetCampaigns.php | 4 +- plugins/Referrers/Reports/GetKeywords.php | 4 +- plugins/Referrers/Reports/GetReferrerType.php | 36 +- plugins/Referrers/Reports/GetSearchEngines.php | 3 +- plugins/Referrers/Reports/GetSocials.php | 11 +- plugins/Referrers/Reports/GetWebsites.php | 5 +- plugins/Referrers/Widgets.php | 24 - plugins/Referrers/Widgets/GetKeywordsForPage.php | 23 + plugins/Referrers/templates/allReferrers.twig | 11 - .../templates/getSearchEnginesAndKeywords.twig | 13 - plugins/Referrers/templates/index.twig | 89 - plugins/Referrers/templates/indexWebsites.twig | 13 - plugins/Resolution/Reports/Base.php | 2 +- plugins/Resolution/Reports/GetConfiguration.php | 8 +- plugins/Resolution/Reports/GetResolution.php | 8 +- plugins/SEO/Widgets.php | 55 - plugins/SEO/Widgets/GetRank.php | 56 + plugins/Transitions/Controller.php | 6 +- plugins/Transitions/lang/en.json | 3 + .../Categories/LocationsSubcategory.php | 19 + plugins/UserCountry/Controller.php | 9 +- plugins/UserCountry/Menu.php | 6 - plugins/UserCountry/Reports/Base.php | 2 +- plugins/UserCountry/Reports/GetCity.php | 5 +- plugins/UserCountry/Reports/GetContinent.php | 17 +- plugins/UserCountry/Reports/GetCountry.php | 3 +- plugins/UserCountry/Reports/GetRegion.php | 4 +- .../templates/getDistinctCountries.twig | 5 + plugins/UserCountry/templates/index.twig | 29 - .../Categories/RealTimeMapSubcategory.php | 19 + plugins/UserCountryMap/Menu.php | 24 - plugins/UserCountryMap/UserCountryMap.php | 17 +- plugins/UserCountryMap/Widgets/GetRealtimeMap.php | 29 + plugins/UserCountryMap/Widgets/GetVisitorMap.php | 23 + plugins/UserCountryMap/templates/visitorMap.twig | 2 +- plugins/UserLanguage/Reports/Base.php | 3 +- plugins/UserLanguage/Reports/GetLanguage.php | 6 +- plugins/UserLanguage/Reports/GetLanguageCode.php | 4 +- plugins/VisitFrequency/Controller.php | 63 +- plugins/VisitFrequency/Menu.php | 19 - plugins/VisitFrequency/Reports/Get.php | 62 +- plugins/VisitFrequency/Widgets.php | 23 - plugins/VisitFrequency/lang/en.json | 10 +- plugins/VisitFrequency/templates/_sparklines.twig | 39 - .../VisitFrequency/templates/getSparklines.twig | 1 - plugins/VisitFrequency/templates/index.twig | 9 - plugins/VisitTime/Categories/TimesSubcategory.php | 19 + plugins/VisitTime/Controller.php | 25 - plugins/VisitTime/Menu.php | 19 - plugins/VisitTime/Reports/Base.php | 2 +- plugins/VisitTime/Reports/GetByDayOfWeek.php | 10 +- .../Reports/GetVisitInformationPerLocalTime.php | 18 +- .../Reports/GetVisitInformationPerServerTime.php | 7 +- plugins/VisitTime/templates/index.twig | 13 - plugins/VisitorInterest/Controller.php | 24 - plugins/VisitorInterest/Menu.php | 20 - plugins/VisitorInterest/Reports/Base.php | 3 +- .../Reports/GetNumberOfVisitsByDaysSinceLast.php | 11 +- .../Reports/GetNumberOfVisitsByVisitCount.php | 1 - .../Reports/GetNumberOfVisitsPerPage.php | 10 +- .../Reports/GetNumberOfVisitsPerVisitDuration.php | 10 +- plugins/VisitorInterest/templates/index.twig | 21 - plugins/VisitsSummary/API.php | 3 +- plugins/VisitsSummary/Controller.php | 134 +- plugins/VisitsSummary/Menu.php | 20 - plugins/VisitsSummary/Reports/Get.php | 147 +- plugins/VisitsSummary/Widgets.php | 22 - plugins/VisitsSummary/Widgets/Index.php | 47 + plugins/VisitsSummary/lang/en.json | 30 +- plugins/Widgetize/Controller.php | 4 +- plugins/Widgetize/templates/iframe.twig | 1 + plugins/Widgetize/templates/index.twig | 1 - plugins/Widgetize/tests/System/WidgetTest.php | 1932 +-- plugins/ZenMode/ZenMode.php | 1 + .../angularjs/zen-mode/zen-mode-disabler.js | 35 + plugins/ZenMode/javascripts/zen-mode.js | 10 +- tests/PHPUnit/Fixtures/OmniFixture.php | 13 +- tests/PHPUnit/Fixtures/UITestFixture.php | 17 +- .../Framework/Mock/Category/Categeories.php | 63 + .../Integration/Category/CategoryListTest.php | 133 + .../DataTable/Filter/PivotByDimensionTest.php | 2 +- .../PHPUnit/Integration/Menu/MenuReportingTest.php | 80 - .../PHPUnit/Integration/Plugin/CategoriesTest.php | 89 + tests/PHPUnit/Integration/Plugin/WidgetsTest.php | 81 + tests/PHPUnit/Integration/Report/ReportsTest.php | 72 + tests/PHPUnit/Integration/ReportTest.php | 148 +- tests/PHPUnit/Integration/WidgetsListTest.php | 147 +- tests/PHPUnit/System/ApiGetReportMetadataTest.php | 1 + tests/PHPUnit/System/AutoSuggestAPITest.php | 2 + ....getAction_flat__API.getProcessedReport_day.xml | 3 +- ...getAction_lastN__API.getProcessedReport_day.xml | 3 +- ...etCategory_flat__API.getProcessedReport_day.xml | 3 +- ...tCategory_lastN__API.getProcessedReport_day.xml | 3 +- ...ts.getName_flat__API.getProcessedReport_day.xml | 3 +- ...s.getName_lastN__API.getProcessedReport_day.xml | 3 +- ...ProcessedMetric__API.getProcessedReport_day.xml | 1 + ...ldKeepEmptyRows__API.getProcessedReport_day.xml | 5 +- ...sits__subtable__API.getProcessedReport_week.xml | 1 + ...ts_hideColumns___API.getProcessedReport_day.xml | 13 + ...ocessedMetrics___API.getProcessedReport_day.xml | 5 +- ...ts_showColumns___API.getProcessedReport_day.xml | 13 + ...Columns_onlyOne__API.getProcessedReport_day.xml | 3 +- ...firstSite_lastN__API.getProcessedReport_day.xml | 10 +- ...rstSite_lastN__API.getProcessedReport_month.xml | 10 +- ...firstSite_lastN__API.getProcessedReport_day.xml | 13 + ...rstSite_lastN__API.getProcessedReport_month.xml | 13 + ...firstSite_lastN__API.getProcessedReport_day.xml | 10 +- ...rstSite_lastN__API.getProcessedReport_month.xml | 10 +- ...firstSite_lastN__API.getProcessedReport_day.xml | 1 + ...rstSite_lastN__API.getProcessedReport_month.xml | 1 + ...firstSite_lastN__API.getProcessedReport_day.xml | 3 +- ...rstSite_lastN__API.getProcessedReport_month.xml | 3 +- ...firstSite_lastN__API.getProcessedReport_day.xml | 3 +- ...rstSite_lastN__API.getProcessedReport_month.xml | 3 +- ...firstSite_lastN__API.getProcessedReport_day.xml | 3 +- ...rstSite_lastN__API.getProcessedReport_month.xml | 3 +- ...firstSite_lastN__API.getProcessedReport_day.xml | 1 + ...rstSite_lastN__API.getProcessedReport_month.xml | 1 + ...firstSite_lastN__API.getProcessedReport_day.xml | 1 + ...firstSite_lastN__API.getProcessedReport_day.xml | 13 + ...firstSite_lastN__API.getProcessedReport_day.xml | 1 + ...firstSite_lastN__API.getProcessedReport_day.xml | 1 + ...firstSite_lastN__API.getProcessedReport_day.xml | 1 + ...firstSite_lastN__API.getProcessedReport_day.xml | 1 + ...firstSite_lastN__API.getProcessedReport_day.xml | 3 +- ...eduledReports.generateReport_month.original.csv | 436 +- ...duledReports.generateReport_month.original.html | 4929 ++++---- ...t_apiGetReportMetadata__API.getMetadata_day.xml | 1 + ...tReportMetadata__API.getProcessedReport_day.xml | 1 + ...etReportMetadata__API.getReportMetadata_day.xml | 2220 ++-- ...tReportMetadata__API.getReportPagesMetadata.xml | 4074 ++++++ ...apiGetReportMetadata__API.getWidgetMetadata.xml | 2694 ++++ ...etReportMetadata__API.getWidgetMetadata_day.xml | 1987 +++ ..._showRawMetrics__API.getProcessedReport_day.xml | 1 + ...tMetadata_year__API.getProcessedReport_year.xml | 1 + ...a_ItemsCategory__API.getProcessedReport_day.xml | 1 + ...tadata_ItemsSku__API.getProcessedReport_day.xml | 1 + ...onPerServerTime__API.getProcessedReport_day.xml | 5 +- ...eOrderWithItems__API.getProcessedReport_day.xml | 1 + ...heduledReports.generateReport_week.original.csv | 1 - ...eduledReports.generateReport_week.original.html | 12575 ++++++++++--------- ...aAndNormalAPI__API.getProcessedReport_range.xml | 1 + ...I_pagesegment__API.getProcessedReport_range.xml | 1 + tests/PHPUnit/Unit/Category/CategoryListTest.php | 92 + tests/PHPUnit/Unit/Category/CategoryTest.php | 141 + tests/PHPUnit/Unit/Category/SubcategoryTest.php | 89 + .../PHPUnit/Unit/Report/ReportWidgetConfigTest.php | 262 + .../Unit/Report/ReportWidgetFactoryTest.php | 112 + tests/PHPUnit/Unit/Widget/WidgetConfigTest.php | 224 + .../Unit/Widget/WidgetContainerConfigTest.php | 280 + tests/PHPUnit/Unit/Widget/WidgetsListTest.php | 177 + tests/UI/diff.png | Bin 0 -> 13648 bytes tests/UI/specs/DashboardManager_spec.js | 6 +- tests/UI/specs/Dashboard_spec.js | 26 +- tests/UI/specs/Menus_spec.js | 21 +- tests/UI/specs/Overlay_spec.js | 2 +- tests/UI/specs/PeriodSelector_spec.js | 3 +- tests/UI/specs/PivotByDimension_spec.js | 6 +- tests/UI/specs/ReportExporting_spec.js | 4 +- tests/UI/specs/SegmentSelectorEditor_spec.js | 7 +- tests/UI/specs/Transitions_spec.js | 4 +- tests/UI/specs/UIIntegration_spec.js | 104 +- .../lib/screenshot-testing/support/chai-extras.js | 8 +- .../screenshot-testing/support/page-renderer.js | 4 +- 450 files changed, 31746 insertions(+), 15336 deletions(-) create mode 100644 core/Category/Category.php create mode 100644 core/Category/CategoryList.php create mode 100644 core/Category/Subcategory.php delete mode 100644 core/Menu/MenuMain.php delete mode 100644 core/Menu/MenuReporting.php create mode 100644 core/Plugin/Categories.php create mode 100644 core/Plugin/Reports.php create mode 100644 core/Report/ReportWidgetConfig.php create mode 100644 core/Report/ReportWidgetFactory.php create mode 100644 core/Updates/3.0.0-b1.php delete mode 100644 core/View/ReportsByDimension.php create mode 100644 core/Widget/Widget.php create mode 100644 core/Widget/WidgetConfig.php create mode 100644 core/Widget/WidgetContainerConfig.php create mode 100644 core/Widget/WidgetsList.php delete mode 100644 core/WidgetsList.php create mode 100644 plugins/API/SegmentMetadata.php create mode 100644 plugins/API/WidgetMetadata.php create mode 100644 plugins/API/tests/Unit/WidgetMetadataTest.php create mode 100644 plugins/Actions/Categories/DownloadsSubcategory.php create mode 100644 plugins/Actions/Categories/EntryPagesSubcategory.php create mode 100644 plugins/Actions/Categories/ExitPagesSubcategory.php create mode 100644 plugins/Actions/Categories/OutlinksSubcategory.php create mode 100644 plugins/Actions/Categories/PageTitlesSubcategory.php create mode 100644 plugins/Actions/Categories/PagesSubcategory.php create mode 100644 plugins/Actions/Categories/SiteSearchSubcategory.php delete mode 100644 plugins/Actions/Controller.php delete mode 100644 plugins/Actions/Menu.php delete mode 100644 plugins/Actions/templates/indexSiteSearch.twig create mode 100644 plugins/Contents/Categories/ContentsSubcategory.php delete mode 100644 plugins/Contents/Controller.php delete mode 100644 plugins/Contents/Menu.php create mode 100644 plugins/Contents/Widgets/ContentsByDimension.php create mode 100644 plugins/Contents/tests/System/expected/.gitkeep create mode 100644 plugins/CoreHome/Categories/ActionsCategory.php create mode 100644 plugins/CoreHome/Categories/DevicesSubcategory.php create mode 100644 plugins/CoreHome/Categories/EngagementSubcategory.php create mode 100644 plugins/CoreHome/Categories/SoftwareSubcategory.php create mode 100644 plugins/CoreHome/Categories/VisitorsCategory.php create mode 100644 plugins/CoreHome/Categories/VisitorsOverviewSubcategory.php delete mode 100644 plugins/CoreHome/Widgets.php create mode 100644 plugins/CoreHome/Widgets/GetDonateForm.php create mode 100644 plugins/CoreHome/Widgets/GetPromoVideo.php create mode 100644 plugins/CoreHome/angularjs/activity-indicator/activityindicator.directive.js create mode 100644 plugins/CoreHome/angularjs/activity-indicator/activityindicator.html create mode 100644 plugins/CoreHome/angularjs/common/filters/escape.js create mode 100644 plugins/CoreHome/angularjs/common/services/global-ajax-queue.js create mode 100644 plugins/CoreHome/angularjs/common/services/piwik-url.js create mode 100644 plugins/CoreHome/angularjs/common/services/report-metadata-model.js create mode 100644 plugins/CoreHome/angularjs/common/services/reporting-pages-model.js create mode 100644 plugins/CoreHome/angularjs/popover-handler/popover-handler.directive.js create mode 100644 plugins/CoreHome/angularjs/reporting-menu/reportingmenu-model.js create mode 100644 plugins/CoreHome/angularjs/reporting-menu/reportingmenu.controller.js create mode 100644 plugins/CoreHome/angularjs/reporting-menu/reportingmenu.directive.html create mode 100644 plugins/CoreHome/angularjs/reporting-menu/reportingmenu.directive.js create mode 100644 plugins/CoreHome/angularjs/reporting-page/reportingpage-model.js create mode 100644 plugins/CoreHome/angularjs/reporting-page/reportingpage.controller.js create mode 100644 plugins/CoreHome/angularjs/reporting-page/reportingpage.directive.html create mode 100644 plugins/CoreHome/angularjs/reporting-page/reportingpage.directive.js create mode 100644 plugins/CoreHome/angularjs/widget-bydimension-container/widget-bydimension-container.directive.html create mode 100644 plugins/CoreHome/angularjs/widget-bydimension-container/widget-bydimension-container.directive.js create mode 100644 plugins/CoreHome/angularjs/widget-container/widgetcontainer.directive.html create mode 100644 plugins/CoreHome/angularjs/widget-container/widgetcontainer.directive.js create mode 100644 plugins/CoreHome/angularjs/widget-loader/widgetloader.directive.html create mode 100644 plugins/CoreHome/angularjs/widget-loader/widgetloader.directive.js create mode 100644 plugins/CoreHome/angularjs/widget/widget.directive.html create mode 100644 plugins/CoreHome/angularjs/widget/widget.directive.js delete mode 100644 plugins/CoreHome/javascripts/menu.js delete mode 100644 plugins/CoreHome/javascripts/menu_init.js delete mode 100644 plugins/CoreHome/templates/ReportsByDimension/_reportsByDimension.twig create mode 100755 plugins/CoreHome/templates/widgetContainer.twig create mode 100644 plugins/CoreVisualizations/Visualizations/Sparklines.php create mode 100644 plugins/CoreVisualizations/Visualizations/Sparklines/Config.php create mode 100644 plugins/CoreVisualizations/templates/_dataTableViz_sparklines.twig create mode 100644 plugins/CoreVisualizations/templates/macros.twig create mode 100644 plugins/CoreVisualizations/tests/Integration/SparklinesConfigTest.php create mode 100644 plugins/CoreVisualizations/tests/Unit/SparklinesConfigTest.php create mode 100644 plugins/CustomVariables/Categories/CustomVariablesSubcategory.php create mode 100644 plugins/Dashboard/Categories/DashboardCategory.php create mode 100644 plugins/Dashboard/angularjs/common/services/dashboards-model.js create mode 100644 plugins/Dashboard/angularjs/dashboard/dashboard.directive.js delete mode 100644 plugins/DevicesDetection/templates/devices.twig delete mode 100644 plugins/DevicesDetection/templates/software.twig create mode 100644 plugins/Ecommerce/Categories/EcommerceCategory.php create mode 100644 plugins/Ecommerce/Categories/EcommerceLogSubcategory.php create mode 100644 plugins/Ecommerce/Categories/EcommerceOverviewSubcategory.php create mode 100644 plugins/Ecommerce/Categories/ProductSubcategory.php create mode 100644 plugins/Ecommerce/Categories/SalesSubcategory.php delete mode 100644 plugins/Ecommerce/Menu.php delete mode 100644 plugins/Ecommerce/Widgets.php create mode 100644 plugins/Ecommerce/Widgets/GetEcommerceLog.php create mode 100644 plugins/Ecommerce/Widgets/ProductsByDimension.php create mode 100644 plugins/Ecommerce/templates/conversionOverview.twig delete mode 100644 plugins/Ecommerce/templates/ecommerceLog.twig create mode 100644 plugins/Ecommerce/templates/getSparklines.twig create mode 100644 plugins/Events/Categories/EventsSubcategory.php delete mode 100644 plugins/Events/Controller.php delete mode 100644 plugins/Events/Menu.php create mode 100644 plugins/Events/Widgets/EventsByDimension.php delete mode 100644 plugins/Events/templates/index.twig delete mode 100644 plugins/ExamplePlugin/Widgets.php create mode 100644 plugins/ExamplePlugin/Widgets/MyExampleWidget.php delete mode 100644 plugins/ExampleRssWidget/Widgets.php create mode 100644 plugins/ExampleRssWidget/Widgets/RssChangelog.php create mode 100644 plugins/ExampleRssWidget/Widgets/RssPiwik.php create mode 100644 plugins/ExampleUI/Categories/ExampleUiCategory.php create mode 100644 plugins/ExampleUI/Reports/Base.php create mode 100644 plugins/ExampleUI/Reports/GetPlanetRatios.php create mode 100644 plugins/ExampleUI/Reports/GetPlanetRatiosWithLogos.php create mode 100644 plugins/ExampleUI/Reports/GetTemperatures.php create mode 100644 plugins/ExampleUI/Reports/GetTemperaturesEvolution.php create mode 100644 plugins/ExampleUI/lang/en.json create mode 100644 plugins/Goals/Categories/AddANewGoalSubcategory.php create mode 100644 plugins/Goals/Categories/GoalsCategory.php create mode 100644 plugins/Goals/Categories/GoalsOverviewSubcategory.php create mode 100644 plugins/Goals/Categories/ManageGoalsSubcategory.php create mode 100644 plugins/Goals/Conversions.php create mode 100644 plugins/Goals/Pages.php delete mode 100644 plugins/Goals/Widgets.php create mode 100644 plugins/Goals/Widgets/AddNewGoal.php create mode 100644 plugins/Goals/Widgets/EditGoals.php delete mode 100644 plugins/Goals/templates/_titleAndEvolutionGraph.twig create mode 100644 plugins/Goals/templates/conversionOverview.twig delete mode 100644 plugins/Goals/templates/getGoalReportView.twig delete mode 100644 plugins/Goals/templates/getOverviewView.twig delete mode 100644 plugins/Insights/Widgets.php create mode 100644 plugins/Insights/Widgets/GetInsightsOverview.php create mode 100644 plugins/Insights/Widgets/GetOverallMoversAndShakers.php create mode 100644 plugins/Live/Categories/LiveCategory.php create mode 100644 plugins/Live/Categories/VisitorLogSubcategory.php delete mode 100644 plugins/Live/Widgets.php create mode 100644 plugins/Live/Widgets/GetVisitorProfilePopup.php create mode 100644 plugins/Live/Widgets/Widget.php create mode 100644 plugins/MultiSites/Categories/MultiSitesCategory.php create mode 100644 plugins/Referrers/Categories/AllReferrersSubcategory.php create mode 100644 plugins/Referrers/Categories/CampaignsSubcategory.php create mode 100644 plugins/Referrers/Categories/ReferrersCategory.php create mode 100644 plugins/Referrers/Categories/ReferrersOverviewSubcategory.php create mode 100644 plugins/Referrers/Categories/SearchEnginesSubcategory.php create mode 100644 plugins/Referrers/Categories/WebsitesSubcategory.php delete mode 100644 plugins/Referrers/Menu.php delete mode 100644 plugins/Referrers/Widgets.php create mode 100644 plugins/Referrers/Widgets/GetKeywordsForPage.php delete mode 100644 plugins/Referrers/templates/allReferrers.twig delete mode 100644 plugins/Referrers/templates/getSearchEnginesAndKeywords.twig delete mode 100644 plugins/Referrers/templates/index.twig delete mode 100644 plugins/Referrers/templates/indexWebsites.twig delete mode 100644 plugins/SEO/Widgets.php create mode 100644 plugins/SEO/Widgets/GetRank.php create mode 100644 plugins/UserCountry/Categories/LocationsSubcategory.php create mode 100644 plugins/UserCountry/templates/getDistinctCountries.twig delete mode 100644 plugins/UserCountry/templates/index.twig create mode 100644 plugins/UserCountryMap/Categories/RealTimeMapSubcategory.php delete mode 100644 plugins/UserCountryMap/Menu.php create mode 100644 plugins/UserCountryMap/Widgets/GetRealtimeMap.php create mode 100644 plugins/UserCountryMap/Widgets/GetVisitorMap.php delete mode 100644 plugins/VisitFrequency/Menu.php delete mode 100644 plugins/VisitFrequency/Widgets.php delete mode 100644 plugins/VisitFrequency/templates/_sparklines.twig delete mode 100644 plugins/VisitFrequency/templates/getSparklines.twig delete mode 100644 plugins/VisitFrequency/templates/index.twig create mode 100644 plugins/VisitTime/Categories/TimesSubcategory.php delete mode 100644 plugins/VisitTime/Controller.php delete mode 100644 plugins/VisitTime/Menu.php delete mode 100644 plugins/VisitTime/templates/index.twig delete mode 100644 plugins/VisitorInterest/Controller.php delete mode 100644 plugins/VisitorInterest/Menu.php delete mode 100644 plugins/VisitorInterest/templates/index.twig delete mode 100644 plugins/VisitsSummary/Menu.php delete mode 100644 plugins/VisitsSummary/Widgets.php create mode 100644 plugins/VisitsSummary/Widgets/Index.php create mode 100644 plugins/ZenMode/angularjs/zen-mode/zen-mode-disabler.js create mode 100644 tests/PHPUnit/Framework/Mock/Category/Categeories.php create mode 100644 tests/PHPUnit/Integration/Category/CategoryListTest.php delete mode 100644 tests/PHPUnit/Integration/Menu/MenuReportingTest.php create mode 100644 tests/PHPUnit/Integration/Plugin/CategoriesTest.php create mode 100644 tests/PHPUnit/Integration/Plugin/WidgetsTest.php create mode 100644 tests/PHPUnit/Integration/Report/ReportsTest.php create mode 100644 tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getReportPagesMetadata.xml create mode 100644 tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getWidgetMetadata.xml create mode 100644 tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getWidgetMetadata_day.xml create mode 100644 tests/PHPUnit/Unit/Category/CategoryListTest.php create mode 100644 tests/PHPUnit/Unit/Category/CategoryTest.php create mode 100644 tests/PHPUnit/Unit/Category/SubcategoryTest.php create mode 100644 tests/PHPUnit/Unit/Report/ReportWidgetConfigTest.php create mode 100644 tests/PHPUnit/Unit/Report/ReportWidgetFactoryTest.php create mode 100644 tests/PHPUnit/Unit/Widget/WidgetConfigTest.php create mode 100644 tests/PHPUnit/Unit/Widget/WidgetContainerConfigTest.php create mode 100644 tests/PHPUnit/Unit/Widget/WidgetsListTest.php create mode 100644 tests/UI/diff.png diff --git a/CHANGELOG.md b/CHANGELOG.md index c1f7965c30..caa2b2ebc0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,29 @@ This is a changelog for Piwik platform developers. All changes for our HTTP API' ## Piwik 3.0.0 +### Breaking Changes +* The menu classes `Piwik\Menu\MenuReporting` and `Piwik\Menu\MenuMain` have been removed +* The class `Piwik\Plugin\Widgets` has been removed and replaced by `Piwik\Widget\Widget`. For each widget one class is needed from now on. You can generate a widget via `./console generate:widget`. +* The class `Piwik\WidgetList` class has been moved to `Piwik\Widget\WidgetsList`. +* The method `Piwik\Plugin\Menu::configureReportingMenu` has been removed. To add something to the reporting menu you need to create widgets +* The method `Report::configureWidget()`, `Report::getWidgetTitle()` and `Report::configureReportingMenu()` have been removed, use the new method `Report::configureWidgets()` instead. +* The method `Report::getCategory()` does no longer return the translated category but the translation key of the category +* The methods `Report::factory()`, `Report::getAllReportClasses()`, `Report::getAllReports` have been moved to the `Piwik\Plugin\Reports` class. +* The properties `Report::$widgetTitle`, `Report::$widgetParams` and `Report::$menuTitle` were removed, use the method `Report::configureWidgets()` to create widgets instead +* In the HTTP API methods `Dashboard.getDefaultDashboard` and `Dashboard.getUserDashboards` we do no longer remove not existing widgets as it is up to the client which widgets actually exist +* The method `Piwik\Plugin\Controller::getEvolutionHtml` has been removed without a replacement as it should be no longer needed. The evolution is generated by ViewDataTables directly + +### New APIs +* Multiple widgets for one report can now be created via the `Report::configureWidgets()` method via the new classes `Piwik\Widget\ReportWidgetFactory` and `Piwik\Widget\ReportWidgetConfig` +* There is a new property `Report::$subCategory` that let's you add a report to the reporting UI. If a page having that name does not exist yet, it will be created automatically. The newly added method `Report::getSubCategory()` let's you get this value. +* The new classes `Piwik\Widget\Widget`, `Piwik\Widget\WidgetConfig` and `Piwik\Widget\WidgetContainerConfig` let's you create a new widget. +* The new class `Piwik\Category\Subcategory` let you change the name and order of menu items +* New HTTP API method `API.getWidgetMetadata` to get a list of available widgets +* New HTTP API method `API.getReportPagesMetadata` to get a list of all available pages that exist including the widgets they include + +### New features +* New "Sparklines" visualization that let's you create a widget showing multiple sparklines + ### Library updates * Updated AngularJS from 1.2.28 to 1.4.3 diff --git a/core/API/DataTableManipulator/ReportTotalsCalculator.php b/core/API/DataTableManipulator/ReportTotalsCalculator.php index 83fef53a27..7906077b1e 100644 --- a/core/API/DataTableManipulator/ReportTotalsCalculator.php +++ b/core/API/DataTableManipulator/ReportTotalsCalculator.php @@ -13,6 +13,7 @@ use Piwik\DataTable; use Piwik\Metrics; use Piwik\Period; use Piwik\Plugin\Report; +use Piwik\Plugin\Reports; /** * This class is responsible for setting the metadata property 'totals' on each dataTable if the report @@ -211,7 +212,8 @@ class ReportTotalsCalculator extends DataTableManipulator private function findFirstLevelReport() { - foreach (Report::getAllReports() as $report) { + $reports = new Reports(); + foreach ($reports->getAllReports() as $report) { $actionToLoadSubtables = $report->getActionToLoadSubTables(); if ($actionToLoadSubtables == $this->apiMethod && $this->apiModule == $report->getModule() diff --git a/core/API/DataTablePostProcessor.php b/core/API/DataTablePostProcessor.php index 9a67311679..c6424ea793 100644 --- a/core/API/DataTablePostProcessor.php +++ b/core/API/DataTablePostProcessor.php @@ -19,6 +19,7 @@ use Piwik\DataTable\Filter\PivotByDimension; use Piwik\Metrics\Formatter; use Piwik\Plugin\ProcessedMetric; use Piwik\Plugin\Report; +use Piwik\Plugin\Reports; /** * Processes DataTables that should be served through Piwik's APIs. This processing handles @@ -71,7 +72,7 @@ class DataTablePostProcessor $this->apiMethod = $apiMethod; $this->setRequest($request); - $this->report = Report::factory($apiModule, $apiMethod); + $this->report = Reports::factory($apiModule, $apiMethod); $this->apiInconsistencies = new Inconsistencies(); $this->setFormatter(new Formatter()); } diff --git a/core/Application/Kernel/EnvironmentValidator.php b/core/Application/Kernel/EnvironmentValidator.php index c8960c48eb..321be28ef1 100644 --- a/core/Application/Kernel/EnvironmentValidator.php +++ b/core/Application/Kernel/EnvironmentValidator.php @@ -11,7 +11,6 @@ namespace Piwik\Application\Kernel; use Piwik\Common; use Piwik\Piwik; use Piwik\SettingsServer; -use Piwik\Translate; use Piwik\Translation\Translator; /** diff --git a/core/Category/Category.php b/core/Category/Category.php new file mode 100644 index 0000000000..cda49032e0 --- /dev/null +++ b/core/Category/Category.php @@ -0,0 +1,100 @@ +order = (int) $order; + return $this; + } + + public function getOrder() + { + return $this->order; + } + + public function setId($id) + { + $this->id = $id; + return $this; + } + + public function getId() + { + return $this->id; + } + + public function addSubcategory(Subcategory $subcategory) + { + $subcategoryId = $subcategory->getId(); + + if ($this->hasSubcategory($subcategoryId)) { + throw new \Exception(sprintf('Subcategory %s already exists', $subcategoryId)); + } + + $this->subcategories[$subcategoryId] = $subcategory; + } + + public function hasSubcategory($subcategoryId) + { + return isset($this->subcategories[$subcategoryId]); + } + + public function getSubcategory($subcategoryId) + { + if ($this->hasSubcategory($subcategoryId)) { + return $this->subcategories[$subcategoryId]; + } + } + + /** + * @return Subcategory[] + */ + public function getSubcategories() + { + return array_values($this->subcategories); + } + + public function hasSubCategories() + { + return !empty($this->subcategories); + } +} \ No newline at end of file diff --git a/core/Category/CategoryList.php b/core/Category/CategoryList.php new file mode 100644 index 0000000000..298d9039ce --- /dev/null +++ b/core/Category/CategoryList.php @@ -0,0 +1,95 @@ +getId(); + + if ($this->hasCategory($categoryId)) { + throw new \Exception(sprintf('Category %s already exists', $categoryId)); + } + + $this->categories[$categoryId] = $category; + } + + public function getCategories() + { + return $this->categories; + } + + public function hasCategory($categoryId) + { + return isset($this->categories[$categoryId]); + } + + /** + * Get the category having the given id, if possible. + * + * @param string $categoryId + * @return Category|null + */ + public function getCategory($categoryId) + { + if ($this->hasCategory($categoryId)) { + return $this->categories[$categoryId]; + } + } + + /** + * @return CategoryList + */ + public static function get() + { + $list = new CategoryList(); + + $categories = StaticContainer::get('Piwik\Plugin\Categories'); + + foreach ($categories->getAllCategories() as $category) { + $list->addCategory($category); + } + + // move subcategories into categories + foreach ($categories->getAllSubcategories() as $subcategory) { + $categoryId = $subcategory->getCategoryId(); + + if (!$categoryId) { + continue; + } + + if ($list->hasCategory($categoryId)) { + $category = $list->getCategory($categoryId); + } else { + $category = new Category(); + $category->setId($categoryId); + $list->addCategory($category); + } + + $category->addSubcategory($subcategory); + } + + return $list; + } +} \ No newline at end of file diff --git a/core/Category/Subcategory.php b/core/Category/Subcategory.php new file mode 100644 index 0000000000..7b6854f95c --- /dev/null +++ b/core/Category/Subcategory.php @@ -0,0 +1,146 @@ +id = $id; + return $this; + } + + /** + * Get the id of the subcategory. + * @return string + */ + public function getId() + { + return $this->id; + } + + /** + * Get the specifed categoryId see {@link $categoryId}. + * + * @return string + */ + public function getCategoryId() + { + return $this->categoryId; + } + + /** + * Sets (overwrites) the categoryId see {@link $categoryId}. + * + * @param string $categoryId + * @return static + */ + public function setCategoryId($categoryId) + { + $this->categoryId = $categoryId; + return $this; + } + + /** + * Sets (overwrites) the name see {@link $name} and {@link $id}. + * + * @param string $name A translation key eg 'General_Overview'. + * @return static + */ + public function setName($name) + { + $this->name = $name; + return $this; + } + + /** + * Get the name of the subcategory. + * @return string + */ + public function getName() + { + if (!empty($this->name)) { + return $this->name; + } + + return $this->id; + } + + /** + * Sets (overwrites) the order see {@link $order}. + * + * @param int $order + * @return static + */ + public function setOrder($order) + { + $this->order = (int) $order; + return $this; + } + + /** + * Get the order of the subcategory. + * @return int + */ + public function getOrder() + { + return $this->order; + } +} \ No newline at end of file diff --git a/core/DataTable/Filter/PivotByDimension.php b/core/DataTable/Filter/PivotByDimension.php index b7f5ca1cf2..bbc72f46d9 100644 --- a/core/DataTable/Filter/PivotByDimension.php +++ b/core/DataTable/Filter/PivotByDimension.php @@ -21,6 +21,7 @@ use Piwik\Period; use Piwik\Piwik; use Piwik\Plugin\Report; use Piwik\Plugin\Segment; +use Piwik\Plugin\Reports; use Piwik\Site; /** @@ -328,7 +329,7 @@ class PivotByDimension extends BaseFilter { list($module, $method) = explode('.', $report); - $this->thisReport = Report::factory($module, $method); + $this->thisReport = Reports::factory($module, $method); if (empty($this->thisReport)) { throw new Exception("Unable to find report '$report'."); } diff --git a/core/Http/ControllerResolver.php b/core/Http/ControllerResolver.php index 569fbee49e..ee1af9acc0 100644 --- a/core/Http/ControllerResolver.php +++ b/core/Http/ControllerResolver.php @@ -10,8 +10,10 @@ namespace Piwik\Http; use DI\FactoryInterface; use Exception; +use Piwik\Plugin; use Piwik\Plugin\Controller; -use Piwik\Plugin\Report; +use Piwik\Plugin\Reports; +use Piwik\Session; use Piwik\Plugin\Widgets; /** @@ -26,9 +28,15 @@ class ControllerResolver */ private $abstractFactory; - public function __construct(FactoryInterface $abstractFactory) + /** + * @var Widgets + */ + private $widgets; + + public function __construct(FactoryInterface $abstractFactory, Widgets $widgets) { $this->abstractFactory = $abstractFactory; + $this->widgets = $widgets; } /** @@ -55,11 +63,6 @@ class ControllerResolver return $controller; } - $controller = $this->createReportMenuController($module, $action, $parameters); - if ($controller) { - return $controller; - } - throw new Exception(sprintf("Action '%s' not found in the module '%s'", $action, $module)); } @@ -84,21 +87,20 @@ class ControllerResolver private function createWidgetController($module, $action, array &$parameters) { - $widget = Widgets::factory($module, $action); + $widget = $this->widgets->factory($module, $action); if (!$widget) { - return null; + return; } $parameters['widget'] = $widget; - $parameters['method'] = $action; return array($this->createCoreHomeController(), 'renderWidget'); } private function createReportController($module, $action, array &$parameters) { - $report = Report::factory($module, $action); + $report = Reports::factory($module, $action); if (!$report) { return null; @@ -109,31 +111,6 @@ class ControllerResolver return array($this->createCoreHomeController(), 'renderReportWidget'); } - private function createReportMenuController($module, $action, array &$parameters) - { - if (!$this->isReportMenuAction($action)) { - return null; - } - - $action = lcfirst(substr($action, 4)); // menuGetPageUrls => getPageUrls - $report = Report::factory($module, $action); - - if (!$report) { - return null; - } - - $parameters['report'] = $report; - - return array($this->createCoreHomeController(), 'renderReportMenu'); - } - - private function isReportMenuAction($action) - { - $startsWithMenu = (Report::PREFIX_ACTION_IN_MENU === substr($action, 0, strlen(Report::PREFIX_ACTION_IN_MENU))); - - return !empty($action) && $startsWithMenu; - } - private function createCoreHomeController() { return $this->abstractFactory->make('Piwik\Plugins\CoreHome\Controller'); diff --git a/core/Menu/MenuMain.php b/core/Menu/MenuMain.php deleted file mode 100644 index adb6b538e9..0000000000 --- a/core/Menu/MenuMain.php +++ /dev/null @@ -1,19 +0,0 @@ -add( - * 'MyPlugin_MyTranslatedMenuCategory', - * 'MyPlugin_MyTranslatedMenuName', - * array('module' => 'MyPlugin', 'action' => 'index'), - * Piwik::isUserHasSomeAdminAccess(), - * $order = 2 - * ); - * } - * - * @api - * @method static \Piwik\Menu\MenuReporting getInstance() - */ -class MenuReporting extends MenuAbstract -{ - - /** - * See {@link add()}. Adds a new menu item to the visitors section of the reporting menu. - * @param string $menuName - * @param array $url - * @param int $order - * @param bool|string $tooltip - * @api - * @since 2.5.0 - */ - public function addVisitorsItem($menuName, $url, $order = 50, $tooltip = false) - { - $this->addItem('General_Visitors', $menuName, $url, $order, $tooltip); - } - - /** - * See {@link add()}. Adds a new menu item to the actions section of the reporting menu. - * @param string $menuName - * @param array $url - * @param int $order - * @param bool|string $tooltip - * @api - * @since 2.5.0 - */ - public function addActionsItem($menuName, $url, $order = 50, $tooltip = false) - { - $this->addItem('General_Actions', $menuName, $url, $order, $tooltip); - } - - /** - * Should not be a public API yet. We probably have to change the API once we have another use case. - * @ignore - */ - public function addGroup($menuName, $defaultTitle, Group $group, $order = 50, $tooltip = false) - { - $this->menuEntries[] = array( - $menuName, - $defaultTitle, - $group, - $order, - $tooltip - ); - } - - /** - * See {@link add()}. Adds a new menu item to the referrers section of the reporting menu. - * @param string $menuName - * @param array $url - * @param int $order - * @param bool|string $tooltip - * @api - * @since 2.5.0 - */ - public function addReferrersItem($menuName, $url, $order = 50, $tooltip = false) - { - $this->addItem('Referrers_Referrers', $menuName, $url, $order, $tooltip); - } - - /** - * Returns if the URL was found in the menu. - * - * @param string $url - * @return boolean - */ - public function isUrlFound($url) - { - $menu = $this->getMenu(); - - foreach ($menu as $subMenus) { - foreach ($subMenus as $subMenuName => $menuUrl) { - if (strpos($subMenuName, '_') !== 0 && $menuUrl['_url'] == $url) { - return true; - } - } - } - return false; - } - - /** - * Triggers the Menu.Reporting.addItems hook and returns the menu. - * - * @return Array - */ - public function getMenu() - { - if (!$this->menu) { - - /** - * @ignore - * @deprecated - */ - Piwik::postEvent('Menu.Reporting.addItems', array()); - - foreach (Report::getAllReports() as $report) { - if ($report->isEnabled()) { - $report->configureReportingMenu($this); - } - } - - foreach ($this->getAllMenus() as $menu) { - $menu->configureReportingMenu($this); - } - } - - return parent::getMenu(); - } -} diff --git a/core/Period/Day.php b/core/Period/Day.php index 4933ddedf6..4ce864df8a 100644 --- a/core/Period/Day.php +++ b/core/Period/Day.php @@ -11,7 +11,6 @@ namespace Piwik\Period; use Exception; use Piwik\Date; use Piwik\Period; -use Piwik\Piwik; /** */ diff --git a/core/Period/Range.php b/core/Period/Range.php index e2b654ca21..1dff3f56ae 100644 --- a/core/Period/Range.php +++ b/core/Period/Range.php @@ -14,7 +14,6 @@ use Piwik\Common; use Piwik\Container\StaticContainer; use Piwik\Date; use Piwik\Period; -use Piwik\Piwik; /** * Arbitrary date range representation. diff --git a/core/Period/Week.php b/core/Period/Week.php index ff2a23a844..d2724694dd 100644 --- a/core/Period/Week.php +++ b/core/Period/Week.php @@ -9,7 +9,6 @@ namespace Piwik\Period; use Piwik\Period; -use Piwik\Piwik; /** */ diff --git a/core/Plugin.php b/core/Plugin.php index ff938a659f..852e09522e 100644 --- a/core/Plugin.php +++ b/core/Plugin.php @@ -490,7 +490,7 @@ class Plugin require_once $file; $fileName = str_replace(array($baseDir . '/', '.php'), '', $file); - $klassName = sprintf('Piwik\\Plugins\\%s\\%s\\%s', $this->pluginName, $directoryWithinPlugin, str_replace('/', '\\', $fileName)); + $klassName = sprintf('Piwik\\Plugins\\%s\\%s\\%s', $this->pluginName, str_replace('/', '\\', $directoryWithinPlugin), str_replace('/', '\\', $fileName)); if (!class_exists($klassName)) { continue; diff --git a/core/Plugin/Categories.php b/core/Plugin/Categories.php new file mode 100644 index 0000000000..4d0543e014 --- /dev/null +++ b/core/Plugin/Categories.php @@ -0,0 +1,71 @@ +pluginManager = $pluginManager; + } + + /** @return \Piwik\Category\Category[] */ + public function getAllCategories() + { + $categories = $this->pluginManager->findMultipleComponents('Categories', '\\Piwik\\Category\\Category'); + + $instances = array(); + foreach ($categories as $category) { + $cat = StaticContainer::getContainer()->make($category); + $instances[$cat->getId()] = $cat; + } + + return $instances; + } + + /** @return \Piwik\Category\Subcategory[] */ + public function getAllSubcategories() + { + $subcategories = array(); + + /** + * Triggered to add custom subcategories. + * + * **Example** + * + * public function addSubcategories(&$subcategories) + * { + * $subcategory = new Subcategory(); + * $subcategory->setId('General_Overview'); + * $subcategory->setCategoryId('General_Visits'); + * $subcategory->setOrder(5); + * $subcategories[] = $subcategory; + * } + * + * @param array &$subcategories An array containing a list of subcategories. + */ + Piwik::postEvent('Category.addSubcategories', array(&$subcategories)); + + $classes = $this->pluginManager->findMultipleComponents('Categories', '\\Piwik\\Category\\Subcategory'); + + foreach ($classes as $subcategory) { + $subcategories[] = StaticContainer::getContainer()->make($subcategory); + } + + return $subcategories; + } +} \ No newline at end of file diff --git a/core/Plugin/Controller.php b/core/Plugin/Controller.php index 3aab8374fb..deeebf234d 100644 --- a/core/Plugin/Controller.php +++ b/core/Plugin/Controller.php @@ -33,6 +33,7 @@ use Piwik\Piwik; use Piwik\Plugins\CoreAdminHome\CustomLogo; use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Evolution; use Piwik\Plugins\LanguagesManager\LanguagesManager; +use Piwik\Plugin\Reports; use Piwik\SettingsPiwik; use Piwik\Site; use Piwik\Url; @@ -313,7 +314,7 @@ abstract class Controller protected function renderReport($apiAction, $controllerAction = false) { if (empty($controllerAction) && is_string($apiAction)) { - $report = Report::factory($this->pluginName, $apiAction); + $report = Reports::factory($this->pluginName, $apiAction); if (!empty($report)) { $apiAction = $report; @@ -949,64 +950,6 @@ abstract class Controller return self::getCalendarPrettyDate(Period\Factory::build($period, Date::factory($date))); } - /** - * Calculates the evolution from one value to another and returns HTML displaying - * the evolution percent. The HTML includes an up/down arrow and is colored red, black or - * green depending on whether the evolution is negative, 0 or positive. - * - * No HTML is returned if the current value and evolution percent are both 0. - * - * @param string $date The date of the current value. - * @param int $currentValue The value to calculate evolution to. - * @param string $pastDate The date of past value. - * @param int $pastValue The value in the past to calculate evolution from. - * @return string|false The HTML or `false` if the evolution is 0 and the current value is 0. - * @api - */ - protected function getEvolutionHtml($date, $currentValue, $pastDate, $pastValue) - { - $evolutionPercent = CalculateEvolutionFilter::calculate( - $currentValue, $pastValue, $precision = 1); - - // do not display evolution if evolution percent is 0 and current value is 0 - if ($evolutionPercent == 0 - && $currentValue == 0 - ) { - return false; - } - - $titleEvolutionPercent = $evolutionPercent; - if ($evolutionPercent < 0) { - $class = "negative-evolution"; - $img = "arrow_down.png"; - } elseif ($evolutionPercent == 0) { - $class = "neutral-evolution"; - $img = "stop.png"; - } else { - $class = "positive-evolution"; - $img = "arrow_up.png"; - $titleEvolutionPercent = '+' . $titleEvolutionPercent; - } - - $title = Piwik::translate('General_EvolutionSummaryGeneric', array( - Piwik::translate('General_NVisits', $currentValue), - $date, - Piwik::translate('General_NVisits', $pastValue), - $pastDate, - $titleEvolutionPercent - )); - - $result = ''; - - return $result; - } - protected function checkSitePermission() { if (!empty($this->idSite) && empty($this->site)) { diff --git a/core/Plugin/Menu.php b/core/Plugin/Menu.php index dd1dcaf7f3..c90e6d851f 100644 --- a/core/Plugin/Menu.php +++ b/core/Plugin/Menu.php @@ -11,11 +11,11 @@ namespace Piwik\Plugin; use Piwik\Common; use Piwik\Development; use Piwik\Menu\MenuAdmin; -use Piwik\Menu\MenuReporting; use Piwik\Menu\MenuTop; use Piwik\Menu\MenuUser; use Piwik\Plugin\Manager as PluginManager; use Piwik\Plugins\UsersManager\UserPreferences; +use Piwik\Plugin\Reports; /** * Base class of all plugin menu providers. Plugins that define their own menu items can extend this class to easily @@ -209,14 +209,6 @@ class Menu ); } - /** - * Configures the reporting menu which should only contain links to reports of a specific site such as - * "Search Engines", "Page Titles" or "Locations & Provider". - */ - public function configureReportingMenu(MenuReporting $menu) - { - } - /** * Configures the top menu which is supposed to contain analytics related items such as the * "All Websites Dashboard". @@ -254,7 +246,7 @@ class Menu } $reportAction = lcfirst(substr($action, 4)); - if (Report::factory($module, $reportAction)) { + if (Reports::factory($module, $reportAction)) { return; } diff --git a/core/Plugin/Report.php b/core/Plugin/Report.php index 5ab8583a5a..716bd92e31 100644 --- a/core/Plugin/Report.php +++ b/core/Plugin/Report.php @@ -11,19 +11,20 @@ namespace Piwik\Plugin; use Piwik\API\Proxy; use Piwik\API\Request; use Piwik\Cache; -use Piwik\CacheId; use Piwik\Columns\Dimension; +use Piwik\Common; use Piwik\DataTable; use Piwik\DataTable\Filter\Sort; -use Piwik\Menu\MenuReporting; use Piwik\Metrics; use Piwik\Cache as PiwikCache; use Piwik\Piwik; -use Piwik\Plugin\Manager as PluginManager; use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable; -use Piwik\WidgetsList; +use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Evolution; +use Piwik\Plugin\Reports; use Piwik\ViewDataTable\Factory as ViewDataTableFactory; use Exception; +use Piwik\Widget\WidgetsList; +use Piwik\Report\ReportWidgetFactory; /** * Defines a new report. This class contains all information a report defines except the corresponding API method which @@ -82,30 +83,14 @@ class Report * @var string * @api */ - protected $category; + protected $categoryId; /** - * The translation key of the widget title. If a widget title is set, the platform will automatically configure/add - * a widget for this report. Alternatively, this behavior can be overwritten in {@link configureWidget()}. + * The translation key of the subcategory the report belongs to. * @var string * @api */ - protected $widgetTitle; - - /** - * Optional widget params that will be appended to the widget URL if a {@link $widgetTitle} is set. - * @var array - * @api - */ - protected $widgetParams = array(); - - /** - * The translation key of the menu title. If a menu title is set, the platform will automatically add a menu item - * to the reporting menu. Alternatively, this behavior can be overwritten in {@link configureReportingMenu()}. - * @var string - * @api - */ - protected $menuTitle; + protected $subcategoryId; /** * An array of supported metrics. Eg `array('nb_visits', 'nb_actions', ...)`. Defaults to the platform default @@ -203,25 +188,6 @@ class Report */ protected $defaultSortOrderDesc = true; - /** - * @var array - * @ignore - */ - public static $orderOfReports = array( - 'General_MultiSitesSummary', - 'VisitsSummary_VisitsSummary', - 'Goals_Ecommerce', - 'General_Actions', - 'Events_Events', - 'Actions_SubmenuSitesearch', - 'Referrers_Referrers', - 'Goals_Goals', - 'General_Visitors', - 'DevicesDetection_DevicesDetection', - 'General_VisitorSettings', - 'API' - ); - /** * The constructur initializes the module, action and the default metrics. If you want to overwrite any of those * values or if you want to do any work during initializing overwrite the method {@link init()}. @@ -229,8 +195,8 @@ class Report */ final public function __construct() { - $classname = get_class($this); - $parts = explode('\\', $classname); + $classname = get_class($this); + $parts = explode('\\', $classname); if (5 === count($parts)) { $this->module = $parts[2]; @@ -268,9 +234,9 @@ class Report * containing a message that will be displayed to the user. You can overwrite this message in case you want to * customize the error message. Eg. * ``` - if (!$this->isEnabled()) { - throw new Exception('Setting XYZ is not enabled or the user has not enough permission'); - } + * if (!$this->isEnabled()) { + * throw new Exception('Setting XYZ is not enabled or the user has not enough permission'); + * } * ``` * @throws \Exception * @api @@ -325,55 +291,29 @@ class Report */ public function render() { + $viewDataTable = Common::getRequestVar('viewDataTable', false, 'string'); + $fixed = Common::getRequestVar('forceView', 0, 'int'); + + $module = $this->getModule(); + $action = $this->getAction(); + $apiProxy = Proxy::getInstance(); - if (!$apiProxy->isExistingApiAction($this->module, $this->action)) { - throw new Exception("Invalid action name '$this->action' for '$this->module' plugin."); + if (!$apiProxy->isExistingApiAction($module, $action)) { + throw new Exception("Invalid action name '$module' for '$action' plugin."); } - $apiAction = $apiProxy->buildApiActionName($this->module, $this->action); - - $view = ViewDataTableFactory::build(null, $apiAction, $this->module . '.' . $this->action); + $apiAction = $apiProxy->buildApiActionName($module, $action); - $rendered = $view->render(); + $view = ViewDataTableFactory::build($viewDataTable, $apiAction, $module . '.' . $action, $fixed); - return $rendered; + return $view->render(); } - /** - * By default a widget will be configured for this report if a {@link $widgetTitle} is set. If you want to customize - * the way the widget is added or modify any other behavior you can overwrite this method. - * @param WidgetsList $widget - * @api - */ - public function configureWidget(WidgetsList $widget) + public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory) { - if ($this->widgetTitle) { - $params = array(); - if (!empty($this->widgetParams) && is_array($this->widgetParams)) { - $params = $this->widgetParams; - } - $widget->add($this->category, $this->widgetTitle, $this->module, $this->action, $params); - } - } - - /** - * By default a menu item will be added to the reporting menu if a {@link $menuTitle} is set. If you want to - * customize the way the item is added or modify any other behavior you can overwrite this method. For instance - * in case you need to add additional url properties beside module and action which are added by default. - * @param \Piwik\Menu\MenuReporting $menu - * @api - */ - public function configureReportingMenu(MenuReporting $menu) - { - if ($this->menuTitle) { - $action = $this->getMenuControllerAction(); - if ($this->isEnabled()) { - $menu->addItem($this->category, - $this->menuTitle, - array('module' => $this->module, 'action' => $action), - $this->order); - } + if ($this->categoryId && $this->subcategoryId) { + $widgetsList->addWidgetConfig($factory->createWidget()); } } @@ -549,11 +489,14 @@ class Report * {@link configureReportMetadata()}. * @return array * @ignore + * + * TODO we should move this out to API::getReportMetadata */ protected function buildReportMetadata() { $report = array( - 'category' => $this->getCategory(), + 'category' => $this->getCategoryId(), + 'subcategory' => $this->getSubcategoryId(), 'name' => $this->getName(), 'module' => $this->getModule(), 'action' => $this->getAction() @@ -587,6 +530,20 @@ class Report $report['constantRowsCount'] = $this->constantRowsCount; } + $relatedReports = $this->getRelatedReports(); + if (!empty($relatedReports)) { + $report['relatedReports'] = array(); + foreach ($relatedReports as $relatedReport) { + if (!empty($relatedReport)) { + $report['relatedReports'][] = array( + 'name' => $relatedReport->getName(), + 'module' => $relatedReport->getModule(), + 'action' => $relatedReport->getAction() + ); + } + } + } + $report['order'] = $this->order; return $report; @@ -624,18 +581,6 @@ class Report return array(); } - /** - * Gets the translated widget title if one is defined. - * @return string - * @ignore - */ - public function getWidgetTitle() - { - if ($this->widgetTitle) { - return Piwik::translate($this->widgetTitle); - } - } - /** * Get the name of the report * @return string @@ -666,24 +611,29 @@ class Report return $this->action; } + public function getParameters() + { + return $this->parameters; + } + /** * Get the translated name of the category the report belongs to. * @return string * @ignore */ - public function getCategory() + public function getCategoryId() { - return Piwik::translate($this->category); + return $this->categoryId; } /** - * Get the translation key of the category the report belongs to. + * Get the translated name of the subcategory the report belongs to. * @return string * @ignore */ - public function getCategoryKey() + public function getSubcategoryId() { - return $this->category; + return $this->subcategoryId; } /** @@ -705,16 +655,6 @@ class Report return $this->order; } - /** - * Get the menu title if one is defined. - * @return string - * @ignore - */ - public function getMenuTitle() - { - return $this->menuTitle; - } - /** * Get the action to load sub tables if one is defined. * @return string @@ -740,7 +680,7 @@ class Report list($subtableReportModule, $subtableReportAction) = $this->getSubtableApiMethod(); - $subtableReport = self::factory($subtableReportModule, $subtableReportAction); + $subtableReport = Reports::factory($subtableReportModule, $subtableReportAction); if (empty($subtableReport)) { return null; } @@ -786,103 +726,6 @@ class Report return Request::processRequest($module . '.' . $action, $paramOverride); } - /** - * Get an instance of a specific report belonging to the given module and having the given action. - * @param string $module - * @param string $action - * @return null|\Piwik\Plugin\Report - * @api - */ - public static function factory($module, $action) - { - $listApiToReport = self::getMapOfModuleActionsToReport(); - $api = $module . '.' . ucfirst($action); - - if (!array_key_exists($api, $listApiToReport)) { - return null; - } - - $klassName = $listApiToReport[$api]; - - return new $klassName; - } - - private static function getMapOfModuleActionsToReport() - { - $cacheId = CacheId::pluginAware('ReportFactoryMap'); - - $cache = Cache::getEagerCache(); - if ($cache->contains($cacheId)) { - $mapApiToReport = $cache->fetch($cacheId); - } else { - $reports = self::getAllReports(); - - $mapApiToReport = array(); - foreach ($reports as $report) { - $key = $report->getModule() . '.' . ucfirst($report->getAction()); - $mapApiToReport[$key] = get_class($report); - } - - $cache->save($cacheId, $mapApiToReport); - } - - return $mapApiToReport; - } - - /** - * Returns a list of all available reports. Even not enabled reports will be returned. They will be already sorted - * depending on the order and category of the report. - * @return \Piwik\Plugin\Report[] - * @api - */ - public static function getAllReports() - { - $reports = self::getAllReportClasses(); - $cacheId = CacheId::languageAware('Reports' . md5(implode('', $reports))); - $cache = PiwikCache::getTransientCache(); - - - if (!$cache->contains($cacheId)) { - $instances = array(); - - foreach ($reports as $report) { - $instances[] = new $report(); - } - - usort($instances, array('self', 'sort')); - - $cache->save($cacheId, $instances); - } - - return $cache->fetch($cacheId); - } - - /** - * Returns class names of all Report metadata classes. - * - * @return string[] - * @api - */ - public static function getAllReportClasses() - { - return PluginManager::getInstance()->findMultipleComponents('Reports', '\\Piwik\\Plugin\\Report'); - } - - /** - * API metadata are sorted by category/name, - * with a little tweak to replicate the standard Piwik category ordering - * - * @param Report $a - * @param Report $b - * @return int - */ - private static function sort($a, $b) - { - return ($category = strcmp(array_search($a->category, self::$orderOfReports), array_search($b->category, self::$orderOfReports))) == 0 - ? ($a->order < $b->order ? -1 : 1) - : $category; - } - private function getMetricTranslations($metricsToTranslate) { $translations = Metrics::getDefaultMetricTranslations(); @@ -903,11 +746,6 @@ class Report return $metrics; } - private function getMenuControllerAction() - { - return self::PREFIX_ACTION_IN_MENU . ucfirst($this->action); - } - private function getSubtableApiMethod() { if (strpos($this->actionToLoadSubTables, '.') !== false) { diff --git a/core/Plugin/Reports.php b/core/Plugin/Reports.php new file mode 100644 index 0000000000..56d69e5453 --- /dev/null +++ b/core/Plugin/Reports.php @@ -0,0 +1,189 @@ +contains($cacheId)) { + $mapApiToReport = $cache->fetch($cacheId); + } else { + $reports = new static(); + $reports = $reports->getAllReports(); + + $mapApiToReport = array(); + foreach ($reports as $report) { + $key = $report->getModule() . '.' . ucfirst($report->getAction()); + + if (isset($mapApiToReport[$key]) && $report->getParameters()) { + // sometimes there are multiple reports with same module/action but different parameters. + // we might pick the "wrong" one. At some point we should compare all parameters and if there is + // a report which parameters mach $_REQUEST then we should prefer that report + continue; + } + $mapApiToReport[$key] = get_class($report); + } + + $cache->save($cacheId, $mapApiToReport); + } + + return $mapApiToReport; + } + + /** + * Returns a list of all available reports. Even not enabled reports will be returned. They will be already sorted + * depending on the order and category of the report. + * @return \Piwik\Plugin\Report[] + * @api + */ + public function getAllReports() + { + $reports = $this->getAllReportClasses(); + $cacheId = CacheId::languageAware('Reports' . md5(implode('', $reports))); + $cache = PiwikCache::getTransientCache(); + + if (!$cache->contains($cacheId)) { + $instances = array(); + + foreach ($reports as $report) { + $instances[] = new $report(); + } + + usort($instances, array($this, 'sort')); + + $cache->save($cacheId, $instances); + } + + return $cache->fetch($cacheId); + } + + /** + * API metadata are sorted by category/name, + * with a little tweak to replicate the standard Piwik category ordering + * + * @param Report $a + * @param Report $b + * @return int + */ + private function sort($a, $b) + { + return $this->compareCategories($a->getCategoryId(), $a->getSubcategoryId(), $a->getOrder(), $b->getCategoryId(), $b->getSubcategoryId(), $b->getOrder()); + } + + public function compareCategories($catIdA, $subcatIdA, $orderA, $catIdB, $subcatIdB, $orderB) + { + static $categoryList; + + if (!isset($categoryList)) { + $categoryList = CategoryList::get(); + } + + $catA = $categoryList->getCategory($catIdA); + $catB = $categoryList->getCategory($catIdB); + + // in case there is a category class for both reports + if (isset($catA) && isset($catB)) { + + if ($catA->getOrder() == $catB->getOrder()) { + // same category order, compare subcategory order + $subcatA = $catA->getSubcategory($subcatIdA); + $subcatB = $catB->getSubcategory($subcatIdB); + + // both reports have a subcategory with custom subcategory class + if ($subcatA && $subcatB) { + if ($subcatA->getOrder() == $subcatB->getOrder()) { + // same subcategory order, compare order of report + + if ($orderA == $orderB) { + return 0; + } + + return $orderA < $orderB ? -1 : 1; + } + + return $subcatA->getOrder() < $subcatB->getOrder() ? -1 : 1; + + } elseif ($subcatA) { + return -1; + } elseif ($subcatB) { + return 1; + } + + if ($orderA == $orderB) { + return 0; + } + + return $orderA < $orderB ? -1 : 1; + } + + return $catA->getOrder() < $catB->getOrder() ? -1 : 1; + + } elseif (isset($catA)) { + return -1; + } elseif (isset($catB)) { + return 1; + } + + if ($catIdA === $catIdB) { + // both have same category, compare order + if ($orderA == $orderB) { + return 0; + } + + return $orderA < $orderB ? -1 : 1; + } + + return strnatcasecmp($catIdA, $catIdB); + } + + /** + * Returns class names of all Report metadata classes. + * + * @return string[] + * @api + */ + public function getAllReportClasses() + { + return Plugin\Manager::getInstance()->findMultipleComponents('Reports', '\\Piwik\\Plugin\\Report'); + } +} \ No newline at end of file diff --git a/core/Plugin/ViewDataTable.php b/core/Plugin/ViewDataTable.php index 6e190388b6..5ca7e2e9ba 100644 --- a/core/Plugin/ViewDataTable.php +++ b/core/Plugin/ViewDataTable.php @@ -13,6 +13,7 @@ use Piwik\Common; use Piwik\DataTable; use Piwik\Period; use Piwik\Piwik; +use Piwik\Plugin\Reports; use Piwik\View; use Piwik\View\ViewInterface; use Piwik\ViewDataTable\Config as VizConfig; @@ -191,7 +192,7 @@ abstract class ViewDataTable implements ViewInterface $this->requestConfig->apiMethodToRequestDataTable = $apiMethodToRequestDataTable; - $report = Report::factory($this->requestConfig->getApiModuleToRequest(), $this->requestConfig->getApiMethodToRequest()); + $report = Reports::factory($this->requestConfig->getApiModuleToRequest(), $this->requestConfig->getApiMethodToRequest()); if (!empty($report)) { /** @var Report $report */ @@ -205,13 +206,7 @@ abstract class ViewDataTable implements ViewInterface $relatedReports = $report->getRelatedReports(); if (!empty($relatedReports)) { foreach ($relatedReports as $relatedReport) { - $widgetTitle = $relatedReport->getWidgetTitle(); - - if ($widgetTitle && Common::getRequestVar('widget', 0, 'int')) { - $relatedReportName = $widgetTitle; - } else { - $relatedReportName = $relatedReport->getName(); - } + $relatedReportName = $relatedReport->getName(); $this->config->addRelatedReport($relatedReport->getModule() . '.' . $relatedReport->getAction(), $relatedReportName); @@ -273,7 +268,7 @@ abstract class ViewDataTable implements ViewInterface $this->overrideViewPropertiesWithQueryParams(); } - protected function assignRelatedReportsTitle() + private function assignRelatedReportsTitle() { if (!empty($this->config->related_reports_title)) { // title already assigned by a plugin @@ -411,12 +406,9 @@ abstract class ViewDataTable implements ViewInterface */ public function render() { - $view = $this->buildView(); - return $view->render(); + return ''; } - abstract protected function buildView(); - protected function getDefaultDataTableCssClass() { return 'dataTableViz' . Piwik::getUnnamespacedClassName(get_class($this)); diff --git a/core/Plugin/Visualization.php b/core/Plugin/Visualization.php index b4ff042932..81e99c9f25 100644 --- a/core/Plugin/Visualization.php +++ b/core/Plugin/Visualization.php @@ -23,6 +23,7 @@ use Piwik\Period; use Piwik\Piwik; use Piwik\Plugins\API\API as ApiApi; use Piwik\Plugins\PrivacyManager\PrivacyManager; +use Piwik\Plugin\Reports; use Piwik\View; use Piwik\ViewDataTable\Manager as ViewDataTableManager; use Piwik\Plugin\Manager as PluginManager; @@ -168,10 +169,10 @@ class Visualization extends ViewDataTable parent::__construct($controllerAction, $apiMethodToRequestDataTable, $params); - $this->report = Report::factory($this->requestConfig->getApiModuleToRequest(), $this->requestConfig->getApiMethodToRequest()); + $this->report = Reports::factory($this->requestConfig->getApiModuleToRequest(), $this->requestConfig->getApiMethodToRequest()); } - protected function buildView() + public function render() { $this->overrideSomeConfigPropertiesIfNeeded(); @@ -233,7 +234,7 @@ class Visualization extends ViewDataTable $view->footerIcons = $this->config->footer_icons; $view->isWidget = Common::getRequestVar('widget', 0, 'int'); - return $view; + return $view->render(); } /** diff --git a/core/Plugin/Widgets.php b/core/Plugin/Widgets.php index 10566a9a7a..e67f2bce61 100644 --- a/core/Plugin/Widgets.php +++ b/core/Plugin/Widgets.php @@ -8,191 +8,162 @@ */ namespace Piwik\Plugin; -use Piwik\Development; -use Piwik\Plugin\Manager as PluginManager; -use Piwik\WidgetsList; +use Piwik\Container\StaticContainer; +use Piwik\Piwik; +use Piwik\Plugin; +use Exception; +use Piwik\Widget\Widget; +use Piwik\Widget\WidgetConfig; +use Piwik\Widget\WidgetContainerConfig; /** - * Base class of all plugin widget providers. Plugins that define their own widgets can extend this class to easily - * add new widgets or to remove widgets defined by other plugins. - * - * For an example, see the {@link https://github.com/piwik/piwik/blob/master/plugins/ExamplePlugin/Widgets.php} plugin. - * - * @api + * Get widgets that are defined by plugins. */ class Widgets { - protected $category = ''; - protected $widgets = array(); - - public function __construct() - { - // Constructor kept for BC (because called in implementations) - } - /** - * @ignore + * @var Plugin\Manager */ - public function getCategory() - { - return $this->category; - } + private $pluginManager; - private function getModule() + public function __construct(Plugin\Manager $pluginManager) { - $className = get_class($this); - $className = explode('\\', $className); - - return $className[2]; - } - - /** - * Adds a widget. You can add a widget by calling this method and passing the name of the widget as well as a method - * name that will be executed to render the widget. The method can be defined either directly here in this widget - * class or in the controller in case you want to reuse the same action for instance in the menu etc. - * @api - */ - protected function addWidget($name, $method, $parameters = array()) - { - $this->addWidgetWithCustomCategory($this->category, $name, $method, $parameters); + $this->pluginManager = $pluginManager; } /** - * Adds a widget with a custom category. By default all widgets that you define in your class will be added under - * the same category which is defined in the {@link $category} property. Sometimes you may have a widget that - * belongs to a different category where this method comes handy. It does the same as {@link addWidget()} but - * allows you to define the category name as well. - * @api + * Get all existing widget configs. + * + * @return WidgetConfig[] */ - protected function addWidgetWithCustomCategory($category, $name, $method, $parameters = array()) + public function getWidgetConfigs() { - $this->checkIsValidWidget($name, $method); - - $this->widgets[] = array('category' => $category, - 'name' => $name, - 'params' => $parameters, - 'method' => $method, - 'module' => $this->getModule()); - } + $widgetClasses = $this->getAllWidgetClassNames(); + + $configs = array(); + + /** + * Triggered to add custom widget configs. To filder widgets have a look at the {@hook Widget.filterWidgets} + * event. + * + * **Example** + * + * public function addWidgetConfigs(&$configs) + * { + * $config = new WidgetConfig(); + * $config->setModule('PluginName'); + * $config->setAction('renderDashboard'); + * $config->setCategoryId('Dashboard_Dashboard'); + * $config->setSubcategoryId('dashboardId'); + * $configs[] = $config; + * } + * + * @param array &$configs An array containing a list of widget config entries. + */ + Piwik::postEvent('Widget.addWidgetConfigs', array(&$configs)); + + foreach ($widgetClasses as $widgetClass) { + $configs[] = $this->getWidgetConfigForClassName($widgetClass); + } - /** - * Here you can add one or multiple widgets. To do so call the method {@link addWidget()} or - * {@link addWidgetWithCustomCategory()}. - * @api - */ - protected function init() - { + return $configs; } /** - * @ignore + * Get all existing widget container configs. + * @return WidgetContainerConfig[] */ - public function getWidgets() + public function getWidgetContainerConfigs() { - $this->widgets = array(); + $configs = array(); - $this->init(); + $widgetContainerConfigs = $this->getAllWidgetContainerConfigClassNames(); + foreach ($widgetContainerConfigs as $widgetClass) { + $configs[] = StaticContainer::get($widgetClass); + } - return $this->widgets; + return $configs; } /** - * Allows you to configure previously added widgets. - * For instance you can remove any widgets defined by any plugin by calling the - * {@link \Piwik\WidgetsList::remove()} method. + * Get the widget defined by the given module and action. * - * @param WidgetsList $widgetsList - * @api - */ - public function configureWidgetsList(WidgetsList $widgetsList) - { - } - - /** - * @return \Piwik\Plugin\Widgets[] - * @ignore - */ - public static function getAllWidgets() - { - return PluginManager::getInstance()->findComponents('Widgets', 'Piwik\\Plugin\\Widgets'); - } - - /** - * @ignore - * @return Widgets|null + * @param string $module Aka plugin name, eg 'CoreHome' + * @param string $action An action eg 'renderMe' + * @return Widget|null + * @throws \Exception Throws an exception if the widget is not enabled. */ - public static function factory($module, $action) + public function factory($module, $action) { if (empty($module) || empty($action)) { return; } - $pluginManager = PluginManager::getInstance(); - try { - if (!$pluginManager->isPluginActivated($module)) { + if (!$this->pluginManager->isPluginActivated($module)) { return; } - $plugin = $pluginManager->getLoadedPlugin($module); + $plugin = $this->pluginManager->getLoadedPlugin($module); } catch (\Exception $e) { // we are not allowed to use possible widgets, plugin is not active return; } - /** @var Widgets $widgetContainer */ - $widgetContainer = $plugin->findComponent('Widgets', 'Piwik\\Plugin\\Widgets'); - - if (empty($widgetContainer)) { - // plugin does not define any widgets, we cannot do anything - return; - } + /** @var Widget[] $widgetContainer */ + $widgets = $plugin->findMultipleComponents('Widgets', 'Piwik\\Widget\\Widget'); - if (!is_callable(array($widgetContainer, $action))) { - // widget does not implement such a method, we cannot do anything - return; + foreach ($widgets as $widgetClass) { + $config = $this->getWidgetConfigForClassName($widgetClass); + if ($config->getAction() === $action) { + $config->checkIsEnabled(); + return StaticContainer::get($widgetClass); + } } + } - // the widget class implements such an action, but we have to check whether it is actually exposed and whether - // it was maybe disabled by another plugin, this is only possible by checking the widgetslist, unfortunately - if (!WidgetsList::isDefined($module, $action)) { - return; - } + private function getWidgetConfigForClassName($widgetClass) + { + /** @var string|Widget $widgetClass */ + $config = new WidgetConfig(); + $config->setModule($this->getModuleFromWidgetClassName($widgetClass)); + $config->setAction($this->getActionFromWidgetClassName($widgetClass)); + $widgetClass::configure($config); - return $widgetContainer; + return $config; } - private function checkIsValidWidget($name, $method) + /** + * @return string[] + */ + private function getAllWidgetClassNames() { - if (!Development::isEnabled()) { - return; - } + return $this->pluginManager->findMultipleComponents('Widgets', 'Piwik\\Widget\\Widget'); + } - if (empty($name)) { - Development::error('No name is defined for added widget having method "' . $method . '" in ' . get_class($this)); - } + private function getModuleFromWidgetClassName($widgetClass) + { + $parts = explode('\\', $widgetClass); - if (Development::isCallableMethod($this, $method)) { - return; - } + return $parts[2]; + } - $controllerClass = 'Piwik\\Plugins\\' . $this->getModule() . '\\Controller'; + private function getActionFromWidgetClassName($widgetClass) + { + $parts = explode('\\', $widgetClass); - if (!Development::methodExists($this, $method) && - !Development::methodExists($controllerClass, $method)) { - Development::error('The added method "' . $method . '" neither exists in "' . get_class($this) . '" nor "' . $controllerClass . '". Make sure to define such a method.'); + if (count($parts) >= 4) { + return lcfirst(end($parts)); } - $definedInClass = get_class($this); - - if (Development::methodExists($controllerClass, $method)) { - if (Development::isCallableMethod($controllerClass, $method)) { - return; - } - - $definedInClass = $controllerClass; - } + return ''; + } - Development::error('The method "' . $method . '" is not callable on "' . $definedInClass . '". Make sure the method is public.'); + /** + * @return string[] + */ + private function getAllWidgetContainerConfigClassNames() + { + return $this->pluginManager->findMultipleComponents('Widgets', 'Piwik\\Widget\\WidgetContainerConfig'); } } diff --git a/core/Report/ReportWidgetConfig.php b/core/Report/ReportWidgetConfig.php new file mode 100644 index 0000000000..cb3b576b4d --- /dev/null +++ b/core/Report/ReportWidgetConfig.php @@ -0,0 +1,92 @@ +viewDataTable = $viewDataTableId; + return $this; + } + + /** + * Forces the usage of the given viewDataTable in order to render the report. + * + * @param string $viewDataTableId eg 'table' or 'graph' + * @return $this + */ + public function forceViewDataTable($viewDataTableId) + { + $this->forceViewDataTable = true; + $this->setDefaultViewDataTable($viewDataTableId); + + return $this; + } + + /** + * Detect whether a defined viewDataTable should be forced in order to render a report. + * @return bool + */ + public function isViewDataTableForced() + { + return $this->forceViewDataTable; + } + + /** + * Get the specified viewDataTable. + * @return string + */ + public function getViewDataTable() + { + return $this->viewDataTable; + } + + /** + * @inheritdoc + */ + public function getParameters() + { + $parameters = parent::getParameters(); + + $defaultParams = array(); + + if ($this->forceViewDataTable) { + $defaultParams['forceView'] = '1'; + } + + if ($this->viewDataTable && + ($this->forceViewDataTable || $this->viewDataTable !== Factory::DEFAULT_VIEW)) { + // URL param is not needed for default view dataTable + $defaultParams['viewDataTable'] = $this->viewDataTable; + } + + return $defaultParams + $parameters; + } + +} \ No newline at end of file diff --git a/core/Report/ReportWidgetFactory.php b/core/Report/ReportWidgetFactory.php new file mode 100644 index 0000000000..b3ea165ec4 --- /dev/null +++ b/core/Report/ReportWidgetFactory.php @@ -0,0 +1,119 @@ +createWidget()` is all one has to do in + * order to create a new widget. + * + * @api since Piwik 3.0.0 + */ +class ReportWidgetFactory +{ + /** + * @var Report + */ + private $report = null; + + /** + * Generates a new report widget factory. + * @param Report $report A report instance, widgets will be created based on the data provided by this report. + */ + public function __construct(Report $report) + { + $this->report = $report; + } + + /** + * Creates a widget based on the specified report in {@link construct()}. + * + * It will automatically use the report's name, categoryId, subcategoryId (if specified), + * defaultViewDataTable, module, action, order and parameters in order to create the widget. + * + * @return ReportWidgetConfig + */ + public function createWidget() + { + $widget = new ReportWidgetConfig(); + $widget->setName($this->report->getName()); + $widget->setCategoryId($this->report->getCategoryId()); + + if ($this->report->getDefaultTypeViewDataTable()) { + $widget->setDefaultViewDataTable($this->report->getDefaultTypeViewDataTable()); + } + + if ($this->report->getSubcategoryId()) { + $widget->setSubcategoryId($this->report->getSubcategoryId()); + } + + $widget->setModule($this->report->getModule()); + $widget->setAction($this->report->getAction()); + + $orderThatListsReportsAtTheEndOfEachCategory = 100 + $this->report->getOrder(); + $widget->setOrder($orderThatListsReportsAtTheEndOfEachCategory); + + $parameters = $this->report->getParameters(); + if (!empty($parameters)) { + $widget->setParameters($parameters); + } + + return $widget; + } + + /** + * Creates a new container widget based on the specified report in {@link construct()}. + * + * It will automatically use the report's categoryId, subcategoryId (if specified) and order in order to + * create the container. + * + * @param string $containerId eg 'Products' or 'Contents' see {Piwik\Widget\WidgetContainerConfig::setId()}. + * Other reports or widgets will be able to add more widgets to this container. + * This is useful when you want to show for example multiple related widgets + * together. + * @return WidgetContainerConfig + */ + public function createContainerWidget($containerId) + { + $widget = new WidgetContainerConfig(); + $widget->setCategoryId($this->report->getCategoryId()); + $widget->setId($containerId); + + if ($this->report->getSubcategoryId()) { + $widget->setSubcategoryId($this->report->getSubcategoryId()); + } + + $orderThatListsReportsAtTheEndOfEachCategory = 100 + $this->report->getOrder(); + $widget->setOrder($orderThatListsReportsAtTheEndOfEachCategory); + + return $widget; + } + + /** + * Creates a custom widget that doesn't use a viewDataTable to render the report but instead a custom + * controller action. Make sure the specified `$action` exists in the plugin's controller. Otherwise + * behaves as {@link createWidget()}. + * + * @param string $action eg 'conversionReports' (requires a method `public function conversionReports()` in + * the plugin's controller). + * @return ReportWidgetConfig + */ + public function createCustomWidget($action) + { + $widget = $this->createWidget(); + $widget->setDefaultViewDataTable(null); + $widget->setAction($action); + + return $widget; + } +} \ No newline at end of file diff --git a/core/Tracker.php b/core/Tracker.php index fa774112c3..d64f1b7fa8 100644 --- a/core/Tracker.php +++ b/core/Tracker.php @@ -12,7 +12,6 @@ use Exception; use Piwik\Plugins\BulkTracking\Tracker\Requests; use Piwik\Plugins\PrivacyManager\Config as PrivacyManagerConfig; use Piwik\Config; -use Piwik\Tests\Framework\TestingEnvironmentVariables; use Piwik\Tracker\Db as TrackerDb; use Piwik\Tracker\Db\DbException; use Piwik\Tracker\Handler; diff --git a/core/Updates/3.0.0-b1.php b/core/Updates/3.0.0-b1.php new file mode 100644 index 0000000000..301bc44a1b --- /dev/null +++ b/core/Updates/3.0.0-b1.php @@ -0,0 +1,351 @@ +fetchAll(sprintf("SELECT DISTINCT idgoal FROM %s", Common::prefixTable('goal'))); + $allDashboards = $db->fetchAll(sprintf("SELECT * FROM %s", Common::prefixTable('user_dashboard'))); + + return $this->getDashboardMigrationSqls($allDashboards, $allGoals); + } + + public function doUpdate(Updater $updater) + { + $updater->executeMigrationQueries(__FILE__, $this->getMigrationQueries($updater)); + } + + private function getDashboardMigrationSqls($allDashboards, $allGoals) + { + $sqls = array(); + + + // update dashboard to use new widgets + $oldWidgets = array( + array ( + 'module' => 'VisitTime', + 'action' => 'getVisitInformationPerServerTime', + 'params' => + array ( + ), + ),array ( + 'module' => 'VisitTime', + 'action' => 'getVisitInformationPerLocalTime', + 'params' => + array ( + ), + ),array ( + 'module' => 'VisitTime', + 'action' => 'getByDayOfWeek', + 'params' => + array ( + ), + ),array ( + 'module' => 'VisitsSummary', + 'action' => 'getEvolutionGraph', + 'params' => + array ( + 'columns' => array ('nb_visits'), + ), + ),array ( + 'module' => 'VisitsSummary', + 'action' => 'getSparklines', + 'params' => + array ( + ), + ),array ( + 'module' => 'VisitsSummary', + 'action' => 'index', + 'params' => + array ( + ), + ),array ( + 'module' => 'Live', + 'action' => 'getVisitorLog', + 'params' => + array ('small' => 1), + ),array ( + 'module' => 'VisitorInterest', + 'action' => 'getNumberOfVisitsPerVisitDuration', + 'params' => + array ( + ), + ),array ( + 'module' => 'VisitorInterest', + 'action' => 'getNumberOfVisitsPerPage', + 'params' => + array ( + ), + ),array ( + 'module' => 'VisitFrequency', + 'action' => 'getSparklines', + 'params' => + array ( + ), + ),array ( + 'module' => 'VisitFrequency', + 'action' => 'getEvolutionGraph', + 'params' => + array ( + 'columns' => array ('nb_visits_returning'), + ), + ),array ( + 'module' => 'DevicesDetection', + 'action' => 'getBrowserEngines', + 'params' => + array ( + ), + ),array ( + 'module' => 'Referrers', + 'action' => 'getReferrerType', + 'params' => + array ( + ), + ),array ( + 'module' => 'Referrers', + 'action' => 'getAll', + 'params' => + array ( + ), + ),array ( + 'module' => 'Referrers', + 'action' => 'getSocials', + 'params' => + array ( + ), + ),array ( + 'module' => 'Goals', + 'action' => 'widgetGoalsOverview', + 'params' => + array ( + ), + ),array ( + 'module' => 'Goals', + 'action' => 'getItemsSku', + 'params' => + array ( + ), + ),array ( + 'module' => 'Goals', + 'action' => 'getItemsName', + 'params' => + array ( + ), + ),array ( + 'module' => 'Goals', + 'action' => 'getItemsCategory', + 'params' => + array ( + ), + ),array ( + 'module' => 'Ecommerce', + 'action' => 'widgetGoalReport', + 'params' => + array ( + 'idGoal' => 'ecommerceOrder', + ), + ), + ); + + foreach ($allGoals as $goal) { + $oldWidgets[] = array ( + 'module' => 'Goals', + 'action' => 'widgetGoalReport', + 'params' => + array ( + 'idGoal' => (int) $goal['idgoal'], + )); + } + + $newWidgets = array( + array ( + 'module' => 'VisitTime', + 'action' => 'getVisitInformationPerServerTime', + 'params' => + array ( + 'viewDataTable' => 'graphVerticalBar', + ), + ),array ( + 'module' => 'VisitTime', + 'action' => 'getVisitInformationPerLocalTime', + 'params' => + array ( + 'viewDataTable' => 'graphVerticalBar', + ), + ),array ( + 'module' => 'VisitTime', + 'action' => 'getByDayOfWeek', + 'params' => + array ( + 'viewDataTable' => 'graphVerticalBar' + ), + ),array ( + 'module' => 'VisitsSummary', + 'action' => 'getEvolutionGraph', + 'params' => + array ( + 'forceView' => '1', + 'viewDataTable' => 'graphEvolution', + ), + ),array ( + 'module' => 'VisitsSummary', + 'action' => 'get', + 'params' => + array ( + 'forceView' => '1', + 'viewDataTable' => 'sparklines', + ), + ),array ( + 'module' => 'CoreHome', + 'action' => 'renderWidgetContainer', + 'uniqueId' => 'widgetVisitOverviewWithGraph', + 'params' => + array ( + 'containerId' => 'VisitOverviewWithGraph', + ), + ),array ( + 'module' => 'Live', + 'action' => 'getLastVisitsDetails', + 'params' => + array ( + 'forceView' => '1', + 'viewDataTable' => 'Piwik\\Plugins\\Live\\VisitorLog', + 'small' => '1', + ), + ),array ( + 'module' => 'VisitorInterest', + 'action' => 'getNumberOfVisitsPerVisitDuration', + 'params' => + array ( + 'viewDataTable' => 'cloud', + ), + ),array ( + 'module' => 'VisitorInterest', + 'action' => 'getNumberOfVisitsPerPage', + 'params' => + array ( + 'viewDataTable' => 'cloud', + ), + ),array ( + 'module' => 'VisitFrequency', + 'action' => 'get', + 'params' => + array ( + 'forceView' => '1', + 'viewDataTable' => 'sparklines' + ), + ),array ( + 'module' => 'VisitFrequency', + 'action' => 'getEvolutionGraph', + 'params' => + array ( + 'forceView' => 1, + 'viewDataTable' => 'graphEvolution', + ), + ),array ( + 'module' => 'DevicesDetection', + 'action' => 'getBrowserEngines', + 'params' => + array ( + 'viewDataTable' => 'graphPie', + ), + ),array ( + 'module' => 'Referrers', + 'action' => 'getReferrerType', + 'params' => + array ( + 'viewDataTable' => 'tableAllColumns', + ), + ),array ( + 'module' => 'Referrers', + 'action' => 'getAll', + 'params' => + array ( + 'viewDataTable' => 'tableAllColumns', + ), + ),array ( + 'module' => 'Referrers', + 'action' => 'getSocials', + 'params' => + array ( + 'viewDataTable' => 'graphPie', + ), + ),array ( + 'module' => 'CoreHome', + 'action' => 'renderWidgetContainer', + 'uniqueId' => 'widgetGoalsOverview', + 'params' => + array ( + 'containerId' => 'GoalsOverview' + ), + ),array ( + 'module' => 'Goals', + 'action' => 'getItemsSku', + 'params' => array (), + ),array ( + 'module' => 'Goals', + 'action' => 'getItemsName', + 'params' => array (), + ),array ( + 'module' => 'Goals', + 'action' => 'getItemsCategory', + 'params' => array (), + ),array ( + 'module' => 'CoreHome', + 'action' => 'renderWidgetContainer', + 'uniqueId' => 'widgetEcommerceOverview', + 'params' => + array ( + 'containerId' => 'EcommerceOverview', + ), + ), + ); + + foreach ($allGoals as $goal) { + $newWidgets[] = array ( + 'module' => 'CoreHome', + 'action' => 'renderWidgetContainer', + 'uniqueId' => 'widgetGoal_' . (int) $goal['idgoal'], + 'params' => + array ( + 'containerId' => 'Goal_' . (int) $goal['idgoal'], + )); + } + + foreach ($allDashboards as $dashboard) { + $dashboardLayout = json_decode($dashboard['layout']); + + $dashboardLayout = Dashboard\Model::replaceDashboardWidgets($dashboardLayout, $oldWidgets, $newWidgets); + + $newLayout = json_encode($dashboardLayout); + if ($newLayout != $dashboard['layout']) { + $sqls["UPDATE " . Common::prefixTable('user_dashboard') . " SET layout = '".addslashes($newLayout)."' WHERE iddashboard = ".$dashboard['iddashboard']] = false; + } + } + + return $sqls; + } +} diff --git a/core/Version.php b/core/Version.php index c9a04c200a..224db01a2c 100644 --- a/core/Version.php +++ b/core/Version.php @@ -20,7 +20,7 @@ final class Version * The current Piwik version. * @var string */ - const VERSION = '2.15.0-b15'; + const VERSION = '3.0.0-b1'; public function isStableVersion($version) { diff --git a/core/View/ReportsByDimension.php b/core/View/ReportsByDimension.php deleted file mode 100644 index dbb59be930..0000000000 --- a/core/View/ReportsByDimension.php +++ /dev/null @@ -1,129 +0,0 @@ -dimensionCategories = array(); - $this->id = $id; - } - - /** - * Adds a report to the list of reports to display. - * - * @param string $category The report's category. Can be a i18n token. - * @param string $title The report's title. Can be a i18n token. - * @param string $action The controller action used to load the report, ie, Referrers.getAll - * @param array $params The list of query parameters to use when loading the report. - * This list overrides query parameters currently in use. For example, - * array('idSite' => 2, 'viewDataTable' => 'goalsTable') - * would mean the goals report for site w/ ID=2 will always be loaded. - */ - public function addReport($category, $title, $action, $params = array()) - { - list($module, $action) = explode('.', $action); - $params = array('module' => $module, 'action' => $action) + $params; - - $categories = $this->dimensionCategories; - $categories[$category][] = array( - 'title' => $title, - 'params' => $params, - 'url' => Url::getCurrentQueryStringWithParametersModified($params) - ); - $this->dimensionCategories = $categories; - } - - /** - * Adds a set of reports to the list of reports to display. - * - * @param array $reports An array containing report information. The array requires - * the 'category', 'title', 'action' and 'params' elements. - * For information on what they should contain, @see addReport. - */ - public function addReports($reports) - { - foreach ($reports as $report) { - $this->addReport($report['category'], $report['title'], $report['action'], $report['params']); - } - } - - /** - * @return string The ID specified in the constructor, usually the plugin name - */ - public function getId() - { - return $this->id; - } - - /** - * Renders this view. - * - * @return string The rendered view. - */ - public function render() - { - /** - * Triggered before rendering {@link ReportsByDimension} views. - * - * Plugins can use this event to configure {@link ReportsByDimension} instances by - * adding or removing reports to display. - * - * @param ReportsByDimension $this The view instance. - */ - Piwik::postEvent('View.ReportsByDimension.render', array($this)); - - $this->firstReport = ""; - - // if there are reports & report categories added, render the first one so we can - // display it initially - $categories = $this->dimensionCategories; - if (!empty($categories)) { - $firstCategory = reset($categories); - $firstReportInfo = reset($firstCategory); - - $oldGet = $_GET; - $oldPost = $_POST; - - foreach ($firstReportInfo['params'] as $key => $value) { - $_GET[$key] = $value; - } - - $_POST = array(); - - $module = $firstReportInfo['params']['module']; - $action = $firstReportInfo['params']['action']; - $this->firstReport = FrontController::getInstance()->fetchDispatch($module, $action); - - $_GET = $oldGet; - $_POST = $oldPost; - } - - return parent::render(); - } -} diff --git a/core/ViewDataTable/Config.php b/core/ViewDataTable/Config.php index e856473d46..22cb8c4429 100644 --- a/core/ViewDataTable/Config.php +++ b/core/ViewDataTable/Config.php @@ -13,8 +13,8 @@ use Piwik\API\Request as ApiRequest; use Piwik\DataTable; use Piwik\DataTable\Filter\PivotByDimension; use Piwik\Metrics; -use Piwik\Plugin\Report; use Piwik\Plugins\API\API; +use Piwik\Plugin\Reports; /** * Contains base display properties for {@link Piwik\Plugin\ViewDataTable}s. Manipulating these @@ -684,7 +684,7 @@ class Config private function setShouldShowPivotBySubtable() { - $report = Report::factory($this->controllerName, $this->controllerAction); + $report = Reports::factory($this->controllerName, $this->controllerAction); if (empty($report)) { $this->show_pivot_by_subtable = false; diff --git a/core/ViewDataTable/Factory.php b/core/ViewDataTable/Factory.php index 43db3161e9..543f1280cf 100644 --- a/core/ViewDataTable/Factory.php +++ b/core/ViewDataTable/Factory.php @@ -12,6 +12,7 @@ use Piwik\Common; use Piwik\Piwik; use Piwik\Plugin\Report; use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable; +use Piwik\Plugin\Reports; /** * Provides a means of creating {@link Piwik\Plugin\ViewDataTable} instances by ID. @@ -58,6 +59,8 @@ use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable; */ class Factory { + const DEFAULT_VIEW = HtmlTable::ID; + /** * Cache for getDefaultTypeViewDataTable result. * @@ -132,7 +135,7 @@ class Factory // Common::getRequestVar removes backslashes from the defaultValue in case magic quotes are enabled. // therefore do not pass this as a default value to getRequestVar() if ('' === $type) { - $type = $defaultType ?: HtmlTable::ID; + $type = $defaultType ?: self::DEFAULT_VIEW; } } else { $type = $defaultViewType; @@ -150,8 +153,8 @@ class Factory return self::createViewDataTableInstance($visualizations[$defaultType], $controllerAction, $apiAction, $params); } - if (array_key_exists(HtmlTable::ID, $visualizations)) { - return self::createViewDataTableInstance($visualizations[HtmlTable::ID], $controllerAction, $apiAction, $params); + if (array_key_exists(self::DEFAULT_VIEW, $visualizations)) { + return self::createViewDataTableInstance($visualizations[self::DEFAULT_VIEW], $controllerAction, $apiAction, $params); } throw new \Exception('No visualization found to render ViewDataTable'); @@ -165,7 +168,7 @@ class Factory private static function getReport($apiAction) { list($module, $action) = explode('.', $apiAction); - $report = Report::factory($module, $action); + $report = Reports::factory($module, $action); return $report; } diff --git a/core/Widget/Widget.php b/core/Widget/Widget.php new file mode 100644 index 0000000000..3a27331bd1 --- /dev/null +++ b/core/Widget/Widget.php @@ -0,0 +1,37 @@ +categoryId = $categoryId; + + return $this; + } + + /** + * Get the id of the category the widget belongs to. + * @return string + */ + public function getCategoryId() + { + return $this->categoryId; + } + + /** + * Set the id of the subcategory the widget belongs to. If a subcategory is specified, the widget + * will be shown in the Piwik reporting UI. The subcategoryId will be used as a translation key for + * the submenu item. + * + * @param string $subcategoryId Usually a translation key, eg 'General_Overview', 'Actions_Pages', ... + * @return static + */ + public function setSubcategoryId($subcategoryId) + { + $this->subcategoryId = $subcategoryId; + + return $this; + } + + public function getSubcategoryId() + { + return $this->subcategoryId; + } + + /** + * Set the module (aka plugin name) of the widget. The correct module is usually detected automatically and + * not needed to be configured manually. + * + * @param string $module eg 'CoreHome' + * @return static + */ + public function setModule($module) + { + $this->module = $module; + + return $this; + } + + public function getModule() + { + return $this->module; + } + + /** + * Set the action of the widget that shall be used in the URL to render the widget. + * The correct action is usually detected automatically and not needed to be configured manually. + * + * @param string $action eg 'renderMyWidget' + * @return static + */ + public function setAction($action) + { + $this->action = $action; + + return $this; + } + + public function getAction() + { + return $this->action; + } + + /** + * Sets (overwrites) the parameters of the widget. These parameters will be added to the URL when rendering the + * widget. You can access these parameters via `Piwik\Common::getRequestVar(...)`. + * + * @param array $parameters eg. ('urlparam' => 'urlvalue') + * @return static + */ + public function setParameters($parameters) + { + $this->parameters = $parameters; + + return $this; + } + + /** + * Add new parameters and only overwrite parameters that have the same name. See {@link setParameters()} + * + * @param array $parameters eg. ('urlparam' => 'urlvalue') + * @return static + */ + public function addParameters($parameters) + { + $this->parameters = array_merge($this->parameters, $parameters); + + return $this; + } + + /** + * Get all URL parameters needed to render this widget. + * @return array Eg ('urlparam' => 'urlvalue'). + */ + public function getParameters() + { + $defaultParams = array( + 'module' => $this->getModule(), + 'action' => $this->getAction() + ); + + return $defaultParams + $this->parameters; + } + + /** + * Set the name of the widget. + * + * @param string $name Usually a translation key, eg 'VisitTime_ByServerTimeWidgetName' + * @return static + */ + public function setName($name) + { + $this->name = $name; + + return $this; + } + + /** + * Get the name of the widget. + * + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * Set the order of the widget. + * + * @param int $order eg. 5 + * @return static + */ + public function setOrder($order) + { + $this->order = (int) $order; + + return $this; + } + + /** + * Returns the order of the widget. + * @return int + */ + public function getOrder() + { + return $this->order; + } + + /** + * Defines whether a widget is enabled or not. For instance some widgets might not be available to every user or + * might depend on a setting (such as Ecommerce) of a site. In such a case you can perform any checks and then + * return `true` or `false`. If your report is only available to users having super user access you can do the + * following: `return Piwik::hasUserSuperUserAccess();` + * @return bool + * @api + */ + public function isEnabled() + { + return $this->isEnabled; + } + + /** + * Enable / disable the widget. See {@link isEnabled()} + * + * @param bool $isEnabled + * @return static + */ + public function setIsEnabled($isEnabled) + { + $this->isEnabled = (bool) $isEnabled; + return $this; + } + + /** + * Enables the widget. See {@link isEnabled()} + */ + public function enable() + { + $this->setIsEnabled(true); + } + + /** + * Disables the widget. See {@link isEnabled()} + */ + public function disable() + { + $this->setIsEnabled(false); + } + + /** + * This method checks whether the widget is available, see {@link isEnabled()}. If not, it triggers an exception + * containing a message that will be displayed to the user. You can overwrite this message in case you want to + * customize the error message. Eg. + * ``` + * if (!$this->isEnabled()) { + * throw new Exception('Setting XYZ is not enabled or the user has not enough permission'); + * } + * ``` + * @throws \Exception + * @api + */ + public function checkIsEnabled() + { + if (!$this->isEnabled()) { + throw new Exception(Piwik::translate('General_ExceptionWidgetNotEnabled')); + } + } + + /** + * Returns the unique id of an widget based on module, action and the set parameters. + * + * @return string + */ + public function getUniqueId() + { + $parameters = $this->getParameters(); + unset($parameters['module']); + unset($parameters['action']); + + return WidgetsList::getWidgetUniqueId($this->getModule(), $this->getAction(), $parameters); + } + + /** + * Sets the widget as not widgetizable {@link isWidgetizeable()}. + * + * @return static + */ + public function setIsNotWidgetizable() + { + $this->isWidgetizable = false; + return $this; + } + + /** + * Sets the widget as widgetizable {@link isWidgetizeable()}. + * + * @return static + */ + public function setIsWidgetizable() + { + $this->isWidgetizable = true; + return $this; + } + + /** + * Detect whether the widget is widgetizable meaning it won't be able to add it to the dashboard and it won't + * be possible to export the widget via an iframe if it is not widgetizable. This is usually not needed but useful + * when you eg want to display a widget within the Piwik UI but not want to have it widgetizable. + * + * @return bool + */ + public function isWidgetizeable() + { + return $this->isWidgetizable; + } + + /** + * If middleware parameters are specified, the corresponding action will be executed before showing the + * actual widget in the UI. Only if this action (can be a controller method or API method) returns JSON `true` + * the widget will be actually shown. It is similar to `isEnabled()` but the specified action is performed each + * time the widget is requested in the UI whereas `isEnabled` is only checked once on the inital page load when + * we load the inital list of widgets. So if your widget's visibility depends on archived data + * (aka idSite/period/date) you should specify middle parameters. This has mainly two reasons: + * + * - This way the inital page load time is faster as we won't have to request archived data on the initial page + * load for widgets that are potentially never shown. + * - We execute that action every time before showing it. As the initial list of widgets is loaded on page load + * it is possible that some archives have no data yet, but at a later time there might be actually archived data. + * As we never reload the initial list of widgets we would still not show the widget even there we should. Example: + * On page load there are no conversions, a few minutes later there might be conversions. As the middleware is + * executed before showing it, we detect correctly that there are now conversions whereas `isEnabled` is only + * checked once on the initial Piwik page load. + * + * @param array $parameters URL parameters eg array('module' => 'Goals', 'action' => 'Conversions') + * @return static + */ + public function setMiddlewareParameters($parameters) + { + $this->middlewareParameters = $parameters; + return $this; + } + + /** + * Get defined middleware parameters (if any). + * + * @return array + */ + public function getMiddlewareParameters() + { + return $this->middlewareParameters; + } + + +} \ No newline at end of file diff --git a/core/Widget/WidgetContainerConfig.php b/core/Widget/WidgetContainerConfig.php new file mode 100644 index 0000000000..258d182ab4 --- /dev/null +++ b/core/Widget/WidgetContainerConfig.php @@ -0,0 +1,131 @@ +id = $id; + return $this; + } + + /** + * Get the id of the widget. + * @return string + */ + public function getId() + { + return $this->id; + } + + /** + * Sets the layout of the container widget. + * + * By default widgets within a container are displayed one after another. In case you want to change this + * behaviour you can specify a layout that will be recognized by the UI. It is not yet possible to define + * custom layouts. + * + * @param string $layout eg 'ByDimension' see {@link Piwik\Plugins\CoreHome\CoreHome::WIDGET_CONTAINER_LAYOUT_BY_DIMENSION} + * @return static + */ + public function setLayout($layout) + { + $this->layout = $layout; + return $this; + } + + /** + * Gets the currently set layout. + * @return string + */ + public function getLayout() + { + return $this->layout; + } + + /** + * Adds a new widget to the container widget. + * + * @param WidgetConfig $widget + * @return static + */ + public function addWidgetConfig(WidgetConfig $widget) + { + $this->widgets[] = $widget; + + return $this; + } + + /** + * Get all added widget configs. + * + * @return WidgetConfig[] + */ + public function getWidgetConfigs() + { + return $this->widgets; + } + + /** + * @inheritdoc + */ + public function getUniqueId() + { + $parameters = $this->getParameters(); + unset($parameters['module']); + unset($parameters['action']); + unset($parameters['containerId']); + + return WidgetsList::getWidgetUniqueId($this->id, '', $parameters); + } + + /** + * @inheritdoc + */ + public function getParameters() + { + $params = parent::getParameters(); + $params['containerId'] = $this->getId(); + return $params; + } + +} \ No newline at end of file diff --git a/core/Widget/WidgetsList.php b/core/Widget/WidgetsList.php new file mode 100644 index 0000000000..dfeb004277 --- /dev/null +++ b/core/Widget/WidgetsList.php @@ -0,0 +1,247 @@ +addContainer($widget); + } elseif (Development::isEnabled()) { + $this->checkIsValidWidget($widget); + } + + $this->widgets[] = $widget; + } + + /** + * Add multiple widget configs at once. See {@link addWidgetConfig()}. + * + * @param WidgetConfig[] $widgets + */ + public function addWidgetConfigs($widgets) + { + foreach ($widgets as $widget) { + $this->addWidgetConfig($widget); + } + } + + private function addContainer(WidgetContainerConfig $containerWidget) + { + $widgetId = $containerWidget->getId(); + + $this->container[$widgetId] = $containerWidget; + + // widgets were added to this container, but the container did not exist yet. + if (isset($this->containerWidgets[$widgetId])) { + foreach ($this->containerWidgets[$widgetId] as $widget) { + $containerWidget->addWidgetConfig($widget); + } + unset($this->containerWidgets[$widgetId]); + } + } + + /** + * Get all added widget configs. + * + * @return WidgetConfig[] + */ + public function getWidgetConfigs() + { + return $this->widgets; + } + + private function checkIsValidWidget(WidgetConfig $widget) + { + if (!$widget->getModule()) { + Development::error('No module is defined for added widget having name "' . $widget->getName()); + } + + if (!$widget->getAction()) { + Development::error('No action is defined for added widget having name "' . $widget->getName()); + } + } + + /** + * Add a widget to a widget container. It doesn't matter whether the container was added to this list already + * or whether the container is added later. As long as a container having the same containerId is added at + * some point the widget will be added to that container. If no container having this id is added the widget + * will not be recognized. + * + * @param string $containerId eg 'Products' or 'Contents'. See {@link WidgetContainerConfig::setId} + * @param WidgetConfig $widget + */ + public function addToContainerWidget($containerId, WidgetConfig $widget) + { + if (isset($this->container[$containerId])) { + $this->container[$containerId]->addWidgetConfig($widget); + } else { + if (!isset($this->containerWidgets[$containerId])) { + $this->containerWidgets[$containerId] = array(); + } + + $this->containerWidgets[$containerId][] = $widget; + } + } + + /** + * Removes one or more widgets from the widget list. + * + * @param string $widgetCategoryId The widget category id. Can be a translation token eg 'General_Visits' + * see {@link WidgetConfig::setCategoryId()}. + * @param string|false $widgetName The name of the widget to remove eg 'VisitTime_ByServerTimeWidgetName'. + * If not supplied, all widgets within that category will be removed. + */ + public function remove($widgetCategoryId, $widgetName = false) + { + foreach ($this->widgets as $index => $widget) { + if ($widget->getCategoryId() === $widgetCategoryId) { + if (!$widgetName || $widget->getName() === $widgetName) { + unset($this->widgets[$index]); + } + } + } + } + + /** + * Returns `true` if a widget exists in the widget list, `false` if otherwise. + * + * @param string $module The controller name of the widget. + * @param string $action The controller action of the widget. + * @return bool + */ + public function isDefined($module, $action) + { + foreach ($this->widgets as $widget) { + if ($widget->getModule() === $module && $widget->getAction() === $action) { + return true; + } + } + + return false; + } + + /** + * Get all widgets defined in the Piwik platform. + * @ignore + * @return static + */ + public static function get() + { + $list = new static; + + $widgets = StaticContainer::get('Piwik\Plugin\Widgets'); + + $widgetContainerConfigs = $widgets->getWidgetContainerConfigs(); + foreach ($widgetContainerConfigs as $config) { + if ($config->isEnabled()) { + $list->addWidgetConfig($config); + } + } + + $widgetConfigs = $widgets->getWidgetConfigs(); + foreach ($widgetConfigs as $widget) { + if ($widget->isEnabled()) { + $list->addWidgetConfig($widget); + } + } + + $reports = StaticContainer::get('Piwik\Plugin\Reports'); + $reports = $reports->getAllReports(); + foreach ($reports as $report) { + if ($report->isEnabled()) { + $factory = new ReportWidgetFactory($report); + $report->configureWidgets($list, $factory); + } + } + + /** + * Triggered to filter widgets. + * + * **Example** + * + * public function addWidgetConfigs(Piwik\Widget\WidgetsList $list) + * { + * $list->remove($category='General_Visits'); // remove all widgets having this category + * } + * + * @param WidgetsList $list An instance of the WidgetsList. You can change the list of widgets this way. + */ + Piwik::postEvent('Widget.filterWidgets', array($list)); + + return $list; + } + + /** + * CAUTION! If you ever change this method, existing updates will fail as they currently use that method! + * If you change the output the uniqueId for existing widgets would not be found anymore + * + * Returns the unique id of an widget with the given parameters + * + * @param $controllerName + * @param $controllerAction + * @param array $customParameters + * @return string + */ + public static function getWidgetUniqueId($controllerName, $controllerAction, $customParameters = array()) + { + $widgetUniqueId = 'widget' . $controllerName . $controllerAction; + + foreach ($customParameters as $name => $value) { + if (is_array($value)) { + // use 'Array' for backward compatibility; + // could we switch to using $value[0]? + $value = 'Array'; + } + $widgetUniqueId .= $name . urlencode($value); + } + + return $widgetUniqueId; + } + +} diff --git a/core/WidgetsList.php b/core/WidgetsList.php deleted file mode 100644 index e91a0f2b38..0000000000 --- a/core/WidgetsList.php +++ /dev/null @@ -1,287 +0,0 @@ - array( - * array(...), // info about first widget in this category - * array(...) // info about second widget in this category, etc. - * ), - * 'Visits' => array( - * array(...), - * array(...) - * ), - * ) - * ``` - */ - public static function get() - { - $cache = self::getCacheForCompleteList(); - $cacheId = self::getCacheId(); - - if (!self::$listCacheToBeInvalidated && $cache->contains($cacheId)) { - return $cache->fetch($cacheId); - } - - self::addWidgets(); - - uksort(self::$widgets, array('Piwik\WidgetsList', '_sortWidgetCategories')); - - $widgets = array(); - foreach (self::$widgets as $key => $v) { - $category = Piwik::translate($key); - - if (isset($widgets[$category])) { - $v = array_merge($widgets[$category], $v); - } - - $widgets[$category] = $v; - } - - $cache->save($cacheId, $widgets); - self::$listCacheToBeInvalidated = false; - - return $widgets; - } - - private static function addWidgets() - { - if (!self::$hookCalled) { - self::$hookCalled = true; - - /** - * @ignore - * @deprecated - */ - Piwik::postEvent('WidgetsList.addWidgets'); - - $widgetsList = self::getInstance(); - - foreach (Report::getAllReports() as $report) { - if ($report->isEnabled()) { - $report->configureWidget($widgetsList); - } - } - - $widgetContainers = Widgets::getAllWidgets(); - foreach ($widgetContainers as $widgetContainer) { - $widgets = $widgetContainer->getWidgets(); - - foreach ($widgets as $widget) { - $widgetsList->add($widget['category'], $widget['name'], $widget['module'], $widget['method'], $widget['params']); - } - } - - foreach ($widgetContainers as $widgetContainer) { - $widgetContainer->configureWidgetsList($widgetsList); - } - } - } - - /** - * Sorting method for widget categories - * - * @param string $a - * @param string $b - * @return bool - */ - protected static function _sortWidgetCategories($a, $b) - { - $order = array( - 'VisitsSummary_VisitsSummary', - 'Live!', - 'General_Visitors', - 'General_VisitorSettings', - 'DevicesDetection_DevicesDetection', - 'General_Actions', - 'Events_Events', - 'Actions_SubmenuSitesearch', - 'Referrers_Referrers', - 'Goals_Goals', - 'Goals_Ecommerce', - '_others_', - 'Example Widgets', - 'ExamplePlugin_exampleWidgets', - ); - - if (($oa = array_search($a, $order)) === false) { - $oa = array_search('_others_', $order); - } - if (($ob = array_search($b, $order)) === false) { - $ob = array_search('_others_', $order); - } - return $oa > $ob; - } - - /** - * Returns the unique id of an widget with the given parameters - * - * @param $controllerName - * @param $controllerAction - * @param array $customParameters - * @return string - */ - public static function getWidgetUniqueId($controllerName, $controllerAction, $customParameters = array()) - { - $widgetUniqueId = 'widget' . $controllerName . $controllerAction; - - foreach ($customParameters as $name => $value) { - if (is_array($value)) { - // use 'Array' for backward compatibility; - // could we switch to using $value[0]? - $value = 'Array'; - } - $widgetUniqueId .= $name . $value; - } - - return $widgetUniqueId; - } - - /** - * Adds a report to the list of dashboard widgets. - * - * @param string $widgetCategory The widget category. This can be a translation token. - * @param string $widgetName The name of the widget. This can be a translation token. - * @param string $controllerName The report's controller name (same as the plugin name). - * @param string $controllerAction The report's controller action method name. - * @param array $customParameters Extra query parameters that should be sent while getting - * this report. - */ - public static function add($widgetCategory, $widgetName, $controllerName, $controllerAction, $customParameters = array()) - { - $widgetName = Piwik::translate($widgetName); - $widgetUniqueId = self::getWidgetUniqueId($controllerName, $controllerAction, $customParameters); - - if (!array_key_exists($widgetCategory, self::$widgets)) { - self::$widgets[$widgetCategory] = array(); - } - - self::$listCacheToBeInvalidated = true; - self::$widgets[$widgetCategory][] = array( - 'name' => $widgetName, - 'uniqueId' => $widgetUniqueId, - 'parameters' => array('module' => $controllerName, - 'action' => $controllerAction - ) + $customParameters - ); - } - - /** - * Removes one or more widgets from the widget list. - * - * @param string $widgetCategory The widget category. Can be a translation token. - * @param string|false $widgetName The name of the widget to remove. Cannot be a - * translation token. If not supplied, the entire category - * will be removed. - */ - public static function remove($widgetCategory, $widgetName = false) - { - if (!isset(self::$widgets[$widgetCategory])) { - return; - } - - if (empty($widgetName)) { - unset(self::$widgets[$widgetCategory]); - self::$listCacheToBeInvalidated = true; - return; - } - foreach (self::$widgets[$widgetCategory] as $id => $widget) { - if ($widget['name'] == $widgetName || $widget['name'] == Piwik::translate($widgetName)) { - unset(self::$widgets[$widgetCategory][$id]); - self::$listCacheToBeInvalidated = true; - return; - } - } - } - - /** - * Returns `true` if a report exists in the widget list, `false` if otherwise. - * - * @param string $controllerName The controller name of the report. - * @param string $controllerAction The controller action of the report. - * @return bool - */ - public static function isDefined($controllerName, $controllerAction) - { - $widgetsList = self::get(); - foreach ($widgetsList as $widgets) { - foreach ($widgets as $widget) { - if ($widget['parameters']['module'] == $controllerName - && $widget['parameters']['action'] == $controllerAction - ) { - return true; - } - } - } - return false; - } - - /** - * Method to reset the widget list - * For testing only - * @ignore - */ - public static function _reset() - { - self::$widgets = array(); - self::$hookCalled = false; - self::getCacheForCompleteList()->delete(self::getCacheId()); - } - - private static function getCacheId() - { - return CacheId::pluginAware('WidgetsList'); - } - - private static function getCacheForCompleteList() - { - return PiwikCache::getTransientCache(); - } -} diff --git a/lang/en.json b/lang/en.json index ff5dd3738b..5cdeef30a8 100644 --- a/lang/en.json +++ b/lang/en.json @@ -166,6 +166,7 @@ "ExceptionReportNotFound": "The requested report does not exist.", "ExceptionWidgetNotFound": "The requested widget does not exist.", "ExceptionReportNotEnabled": "The requested report is not enabled. This means usually either the plugin that defines the report is deactivated or you do not have enough permission to access this report.", + "ExceptionWidgetNotEnabled": "The requested widget is not enabled. This means usually either the plugin that defines the widget is deactivated or you do not have enough permission to access this widget.", "ExpandDataTableFooter": "Change the visualization or configure the report", "Export": "Export", "ExportAsImage": "Export as Image", diff --git a/misc/others/iframeWidget_localhost.php b/misc/others/iframeWidget_localhost.php index 73bfc5c59b..a124b9767a 100644 --- a/misc/others/iframeWidget_localhost.php +++ b/misc/others/iframeWidget_localhost.php @@ -2,7 +2,7 @@ use Piwik\FrontController; use Piwik\Url; use Piwik\UrlHelper; -use Piwik\WidgetsList; +use Piwik\Widget\WidgetsList; exit; $date = date('Y-m-d'); @@ -34,15 +34,28 @@ require_once PIWIK_INCLUDE_PATH . "/index.php"; require_once PIWIK_INCLUDE_PATH . "/core/API/Request.php"; FrontController::getInstance()->init(); -$widgets = WidgetsList::get(); -foreach ($widgets as $category => $widgetsInCategory) { +$widgets = WidgetsList::get()->getWidgetConfigs(); +$widgetCategoriesHandled = array(); +foreach ($widgets as $widgetConfig) { + $category = $widgetConfig->getCategoryId(); + + if (!empty($widgetCategoriesHandled[$category])) { + continue; + } + $widgetCategoriesHandled[$category] = true; + echo '

' . $category . '

'; - foreach ($widgetsInCategory as $widget) { - echo '

' . $widget['name'] . '

'; + + foreach ($widgets as $widget) { + if ($category !== $widget->getCategoryId()) { + continue; + } + + echo '

' . \Piwik\Piwik::translate($widget->getName()) . '

'; $widgetUrl = UrlHelper::getArrayFromQueryString($url); - $widgetUrl['moduleToWidgetize'] = $widget['parameters']['module']; - $widgetUrl['actionToWidgetize'] = $widget['parameters']['action']; - $parameters = $widget['parameters']; + $widgetUrl['moduleToWidgetize'] = $widget->getModule(); + $widgetUrl['actionToWidgetize'] = $widget->getAction(); + $parameters = $widget->getParameters(); unset($parameters['module']); unset($parameters['action']); foreach ($parameters as $name => $value) { @@ -54,7 +67,7 @@ foreach ($widgets as $category => $widgetsInCategory) { $widgetUrl = Url::getQueryStringFromParameters($widgetUrl); echo '
'; + src="' . $widgetUrl . '" scrolling="no" frameborder="0" marginheight="0" marginwidth="0">'; } } diff --git a/plugins/API/API.php b/plugins/API/API.php index 4ea0cb4055..8245d0712e 100644 --- a/plugins/API/API.php +++ b/plugins/API/API.php @@ -10,7 +10,10 @@ namespace Piwik\Plugins\API; use Piwik\API\Proxy; use Piwik\API\Request; -use Piwik\Columns\Dimension; +use Piwik\Cache; +use Piwik\CacheId; +use Piwik\Category\CategoryList; +use Piwik\Common; use Piwik\Config; use Piwik\Container\StaticContainer; use Piwik\DataTable; @@ -23,11 +26,13 @@ use Piwik\Period; use Piwik\Period\Range; use Piwik\Piwik; use Piwik\Plugin\Dimension\VisitDimension; +use Piwik\Plugin\Report; use Piwik\Plugins\API\DataTable\MergeDataTables; use Piwik\Plugins\CoreAdminHome\CustomLogo; use Piwik\Translation\Translator; use Piwik\Measurable\Type\TypeManager; use Piwik\Version; +use Piwik\Widget\WidgetsList; require_once PIWIK_INCLUDE_PATH . '/core/Config.php'; @@ -122,83 +127,20 @@ class API extends \Piwik\Plugin\API { $isAuthenticatedWithViewAccess = Piwik::isUserHasViewAccess($idSites) && !Piwik::isUserIsAnonymous(); - $segments = array(); - foreach (Dimension::getAllDimensions() as $dimension) { - foreach ($dimension->getSegments() as $segment) { - if ($segment->isRequiresAtLeastViewAccess()) { - $segment->setPermission($isAuthenticatedWithViewAccess); - } + $sites = (is_array($idSites) ? implode('.', $idSites) : (int) $idSites); + $cache = Cache::getTransientCache(); + $cachKey = 'API.getSegmentsMetadata' . $sites . '_' . (int) $_hideImplementationData . '_' . (int) $isAuthenticatedWithViewAccess; + $cachKey = CacheId::pluginAware($cachKey); - $segments[] = $segment->toArray(); - } + if ($cache->contains($cachKey)) { + return $cache->fetch($cachKey); } - /** - * Triggered when gathering all available segment dimensions. - * - * This event can be used to make new segment dimensions available. - * - * **Example** - * - * public function getSegmentsMetadata(&$segments, $idSites) - * { - * $segments[] = array( - * 'type' => 'dimension', - * 'category' => Piwik::translate('General_Visit'), - * 'name' => 'General_VisitorIP', - * 'segment' => 'visitIp', - * 'acceptedValues' => '13.54.122.1, etc.', - * 'sqlSegment' => 'log_visit.location_ip', - * 'sqlFilter' => array('Piwik\IP', 'P2N'), - * 'permission' => $isAuthenticatedWithViewAccess, - * ); - * } - * - * @param array &$dimensions The list of available segment dimensions. Append to this list to add - * new segments. Each element in this list must contain the - * following information: - * - * - **type**: Either `'metric'` or `'dimension'`. `'metric'` means - * the value is a numeric and `'dimension'` means it is - * a string. Also, `'metric'` values will be displayed - * under **Visit (metrics)** in the Segment Editor. - * - **category**: The segment category name. This can be an existing - * segment category visible in the segment editor. - * - **name**: The pretty name of the segment. Can be a translation token. - * - **segment**: The segment name, eg, `'visitIp'` or `'searches'`. - * - **acceptedValues**: A string describing one or two exacmple values, eg - * `'13.54.122.1, etc.'`. - * - **sqlSegment**: The table column this segment will segment by. - * For example, `'log_visit.location_ip'` for the - * **visitIp** segment. - * - **sqlFilter**: A PHP callback to apply to segment values before - * they are used in SQL. - * - **permission**: True if the current user has view access to this - * segment, false if otherwise. - * @param array $idSites The list of site IDs we're getting the available segments - * for. Some segments (such as Goal segments) depend on the - * site. - */ - Piwik::postEvent('API.getSegmentDimensionMetadata', array(&$segments, $idSites)); - - foreach ($segments as &$segment) { - $segment['name'] = Piwik::translate($segment['name']); - $segment['category'] = Piwik::translate($segment['category']); - - if ($_hideImplementationData) { - unset($segment['sqlFilter']); - unset($segment['sqlFilterValue']); - unset($segment['sqlSegment']); - - if (isset($segment['suggestedValuesCallback']) - && !is_string($segment['suggestedValuesCallback']) - ) { - unset($segment['suggestedValuesCallback']); - } - } - } + $metadata = new SegmentMetadata(); + $segments = $metadata->getSegmentsMetadata($idSites, $_hideImplementationData, $isAuthenticatedWithViewAccess); + + $cache->save($cachKey, $segments); - usort($segments, array($this, 'sortSegments')); return $segments; } @@ -219,32 +161,6 @@ class API extends \Piwik\Plugin\API return $values; } - private function sortSegments($row1, $row2) - { - $customVarCategory = Piwik::translate('CustomVariables_CustomVariables'); - - $columns = array('type', 'category', 'name', 'segment'); - foreach ($columns as $column) { - // Keep segments ordered alphabetically inside categories.. - $type = -1; - if ($column == 'name') $type = 1; - - $compare = $type * strcmp($row1[$column], $row2[$column]); - - // hack so that custom variables "page" are grouped together in the doc - if ($row1['category'] == $customVarCategory - && $row1['category'] == $row2['category'] - ) { - $compare = strcmp($row1['segment'], $row2['segment']); - return $compare; - } - if ($compare != 0) { - return $compare; - } - } - return $compare; - } - /** * Returns the url to application logo (~280x110px) * @@ -342,6 +258,41 @@ class API extends \Piwik\Plugin\API return $processed; } + /** + * Get a list of all pages that shall be shown in a Piwik UI including a list of all widgets that shall + * be shown within each page. + * + * @param int $idSite + * @return array + */ + public function getReportPagesMetadata($idSite) + { + Piwik::checkUserHasViewAccess($idSite); + + $widgetsList = WidgetsList::get(); + $categoryList = CategoryList::get(); + $metadata = new WidgetMetadata(); + + return $metadata->getPagesMetadata($categoryList, $widgetsList); + } + + /** + * Get a list of all widgetizable widgets. + * + * @param int $idSite + * @return array + */ + public function getWidgetMetadata($idSite) + { + Piwik::checkUserHasViewAccess($idSite); + + $widgetsList = WidgetsList::get(); + $categoryList = CategoryList::get(); + $metadata = new WidgetMetadata(); + + return $metadata->getWidgetMetadata($categoryList, $widgetsList); + } + /** * Get a combined report of the *.get API methods. */ @@ -555,7 +506,12 @@ class API extends \Piwik\Plugin\API if ($suggestedValuesCallbackRequiresTable) { $values = call_user_func($segmentFound['suggestedValuesCallback'], $idSite, $maxSuggestionsToReturn, $table); } else { - $values = $this->getSegmentValuesFromVisitorLog($segmentName, $table); + // Cleanup data to return the top suggested (non empty) labels for this segment + $values = $table->getColumn($segmentName); + + // Select also flattened keys (custom variables "page" scope, page URLs for one visit, page titles for one visit) + $valuesBis = $table->getColumnsStartingWith($segmentName . ColumnDelete::APPEND_TO_COLUMN_NAME_TO_KEEP); + $values = array_merge($values, $valuesBis); } $values = $this->getMostFrequentValues($values); @@ -600,9 +556,7 @@ class API extends \Piwik\Plugin\API // If you update this, also update flattenVisitorDetailsArray $segmentsNeedActionsInfo = array('visitConvertedGoalId', 'pageUrl', 'pageTitle', 'siteSearchKeyword', - 'entryPageTitle', 'entryPageUrl', 'exitPageTitle', 'exitPageUrl', - 'outlinkUrl', 'downloadUrl' - ); + 'entryPageTitle', 'entryPageUrl', 'exitPageTitle', 'exitPageUrl'); $isCustomVariablePage = stripos($segmentName, 'customVariablePage') !== false; $isEventSegment = stripos($segmentName, 'event') !== false; $isContentSegment = stripos($segmentName, 'content') !== false; diff --git a/plugins/API/ProcessedReport.php b/plugins/API/ProcessedReport.php index d9d315b4c0..65b59a2051 100644 --- a/plugins/API/ProcessedReport.php +++ b/plugins/API/ProcessedReport.php @@ -23,9 +23,11 @@ use Piwik\Metrics\Formatter; use Piwik\Period; use Piwik\Piwik; use Piwik\Plugin\Report; +use Piwik\Plugin\Reports; use Piwik\Site; use Piwik\Timer; use Piwik\Url; +use Piwik\Category\Category; class ProcessedReport { @@ -166,77 +168,14 @@ class ProcessedReport $availableReports = array(); - foreach (Report::getAllReports() as $report) { + $reports = new Reports(); + foreach ($reports->getAllReports() as $report) { $report->configureReportMetadata($availableReports, $parameters); } - /** - * Triggered when gathering metadata for all available reports. - * - * Plugins that define new reports should use this event to make them available in via - * the metadata API. By doing so, the report will become available in scheduled reports - * as well as in the Piwik Mobile App. In fact, any third party app that uses the metadata - * API will automatically have access to the new report. - * - * @param string &$availableReports The list of available reports. Append to this list - * to make a report available. - * - * Every element of this array must contain the following - * information: - * - * - **category**: A translated string describing the report's category. - * - **name**: The translated display title of the report. - * - **module**: The plugin of the report. - * - **action**: The API method that serves the report. - * - * The following information is optional: - * - * - **dimension**: The report's [dimension](/guides/all-about-analytics-data#dimensions) if any. - * - **metrics**: An array mapping metric names with their display names. - * - **metricsDocumentation**: An array mapping metric names with their - * translated documentation. - * - **processedMetrics**: The array of metrics in the report that are - * calculated using existing metrics. Can be set to - * `false` if the report contains no processed - * metrics. - * - **order**: The order of the report in the list of reports - * with the same category. - * - * @param array $parameters Contains the values of the sites and period we are - * getting reports for. Some reports depend on this data. - * For example, Goals reports depend on the site IDs being - * requested. Contains the following information: - * - * - **idSites**: The array of site IDs we are getting reports for. - * - **period**: The period type, eg, `'day'`, `'week'`, `'month'`, - * `'year'`, `'range'`. - * - **date**: A string date within the period or a date range, eg, - * `'2013-01-01'` or `'2012-01-01,2013-01-01'`. - * - * TODO: put dimensions section in all about analytics data - * @deprecated since 2.5.0 Use Report Classes instead. - * @ignore - */ - Piwik::postEvent('API.getReportMetadata', array(&$availableReports, $parameters)); - - // TODO we can remove this one once we remove API.getReportMetadata event (except hideMetricsDoc) foreach ($availableReports as &$availableReport) { - // can be removed once we remove hook API.getReportMetadata - if (!isset($availableReport['metrics'])) { - $availableReport['metrics'] = Metrics::getDefaultMetrics(); - } - // can be removed once we remove hook API.getReportMetadata - if (!isset($availableReport['processedMetrics'])) { - $availableReport['processedMetrics'] = Metrics::getDefaultProcessedMetrics(); - } - - if ($hideMetricsDoc) // remove metric documentation if it's not wanted - { + if ($hideMetricsDoc) { unset($availableReport['metricsDocumentation']); - } else if (!isset($availableReport['metricsDocumentation'])) { - // set metric documentation to default if it's not set - // can be removed once we remove hook API.getReportMetadata - $availableReport['metricsDocumentation'] = Metrics::getDefaultMetricsDocumentation(); } } @@ -270,6 +209,9 @@ class ProcessedReport $columnsToRemove = $this->getColumnsToRemove(); foreach ($availableReports as &$availableReport) { + $availableReport['category'] = Piwik::translate($availableReport['category']); + $availableReport['subcategory'] = Piwik::translate($availableReport['subcategory']); + // Ensure all metrics have a translation $metrics = $availableReport['metrics']; $cleanedMetrics = array(); @@ -349,16 +291,8 @@ class ProcessedReport */ private static function sortReports($a, $b) { - static $order = null; - if (is_null($order)) { - $order = array(); - foreach (Report::$orderOfReports as $category) { - $order[] = Piwik::translate($category); - } - } - return ($category = strcmp(array_search($a['category'], $order), array_search($b['category'], $order))) == 0 - ? (@$a['order'] < @$b['order'] ? -1 : 1) - : $category; + $reports = new Reports(); + return $reports->compareCategories($a['category'], $a['subcategory'], $a['order'], $b['category'], $b['subcategory'], $b['order']); } public function getProcessedReport($idSite, $period, $date, $apiModule, $apiAction, $segment = false, diff --git a/plugins/API/Reports/Get.php b/plugins/API/Reports/Get.php index de087d0a86..61cded3856 100644 --- a/plugins/API/Reports/Get.php +++ b/plugins/API/Reports/Get.php @@ -10,6 +10,7 @@ namespace Piwik\Plugins\API\Reports; use Piwik\Piwik; use Piwik\Plugin\Report; +use Piwik\Plugin\Reports; class Get extends Report { @@ -29,7 +30,7 @@ class Get extends Report $this->module = 'API'; $this->action = 'get'; - $this->category = 'API'; + $this->categoryId = 'API'; $this->name = Piwik::translate('General_MainMetrics'); $this->documentation = ''; @@ -80,8 +81,9 @@ class Get extends Report */ private function getReportsToMerge() { + $reports = new Reports(); $result = array(); - foreach (Report::getAllReportClasses() as $reportClass) { + foreach ($reports->getAllReportClasses() as $reportClass) { if ($reportClass == 'Piwik\\Plugins\\API\\Reports\\Get') { continue; } diff --git a/plugins/API/SegmentMetadata.php b/plugins/API/SegmentMetadata.php new file mode 100644 index 0000000000..9d7e563bfb --- /dev/null +++ b/plugins/API/SegmentMetadata.php @@ -0,0 +1,167 @@ +getSegments() as $segment) { + $segments[] = $segment->toArray(); + } + } + + /** + * Triggered when gathering all available segment dimensions. + * + * This event can be used to make new segment dimensions available. + * + * **Example** + * + * public function getSegmentsMetadata(&$segments, $idSites) + * { + * $segments[] = array( + * 'type' => 'dimension', + * 'category' => Piwik::translate('General_Visit'), + * 'name' => 'General_VisitorIP', + * 'segment' => 'visitIp', + * 'acceptedValues' => '13.54.122.1, etc.', + * 'sqlSegment' => 'log_visit.location_ip', + * 'sqlFilter' => array('Piwik\IP', 'P2N'), + * 'permission' => $isAuthenticatedWithViewAccess, + * ); + * } + * + * @param array &$dimensions The list of available segment dimensions. Append to this list to add + * new segments. Each element in this list must contain the + * following information: + * + * - **type**: Either `'metric'` or `'dimension'`. `'metric'` means + * the value is a numeric and `'dimension'` means it is + * a string. Also, `'metric'` values will be displayed + * under **Visit (metrics)** in the Segment Editor. + * - **category**: The segment category name. This can be an existing + * segment category visible in the segment editor. + * - **name**: The pretty name of the segment. Can be a translation token. + * - **segment**: The segment name, eg, `'visitIp'` or `'searches'`. + * - **acceptedValues**: A string describing one or two exacmple values, eg + * `'13.54.122.1, etc.'`. + * - **sqlSegment**: The table column this segment will segment by. + * For example, `'log_visit.location_ip'` for the + * **visitIp** segment. + * - **sqlFilter**: A PHP callback to apply to segment values before + * they are used in SQL. + * - **permission**: True if the current user has view access to this + * segment, false if otherwise. + * @param array $idSites The list of site IDs we're getting the available segments + * for. Some segments (such as Goal segments) depend on the + * site. + */ + Piwik::postEvent('API.getSegmentDimensionMetadata', array(&$segments, $idSites)); + + $segments[] = array( + 'type' => 'dimension', + 'category' => Piwik::translate('General_Visit'), + 'name' => 'General_UserId', + 'segment' => 'userId', + 'acceptedValues' => 'any non empty unique string identifying the user (such as an email address or a username).', + 'sqlSegment' => 'log_visit.user_id', + 'permission' => $isAuthenticatedWithViewAccess, + ); + + $segments[] = array( + 'type' => 'dimension', + 'category' => Piwik::translate('General_Visit'), + 'name' => 'General_VisitorID', + 'segment' => 'visitorId', + 'acceptedValues' => '34c31e04394bdc63 - any 16 Hexadecimal chars ID, which can be fetched using the Tracking API function getVisitorId()', + 'sqlSegment' => 'log_visit.idvisitor', + 'sqlFilterValue' => array('Piwik\Common', 'convertVisitorIdToBin'), + 'permission' => $isAuthenticatedWithViewAccess, + ); + + $segments[] = array( + 'type' => 'dimension', + 'category' => Piwik::translate('General_Visit'), + 'name' => Piwik::translate('General_Visit') . " ID", + 'segment' => 'visitId', + 'acceptedValues' => 'Any integer. ', + 'sqlSegment' => 'log_visit.idvisit', + 'permission' => $isAuthenticatedWithViewAccess, + ); + + $segments[] = array( + 'type' => 'metric', + 'category' => Piwik::translate('General_Visit'), + 'name' => 'General_VisitorIP', + 'segment' => 'visitIp', + 'acceptedValues' => '13.54.122.1. Select IP ranges with notation: visitIp>13.54.122.0;visitIp<13.54.122.255', + 'sqlSegment' => 'log_visit.location_ip', + 'sqlFilterValue' => array('Piwik\Network\IPUtils', 'stringToBinaryIP'), + 'permission' => $isAuthenticatedWithViewAccess, + ); + + foreach ($segments as &$segment) { + $segment['name'] = Piwik::translate($segment['name']); + $segment['category'] = Piwik::translate($segment['category']); + + if ($_hideImplementationData) { + unset($segment['sqlFilter']); + unset($segment['sqlFilterValue']); + unset($segment['sqlSegment']); + } + + if (isset($segment['suggestedValuesCallback']) + && !is_string($segment['suggestedValuesCallback']) + ) { + unset($segment['suggestedValuesCallback']); + } + } + + usort($segments, array($this, 'sortSegments')); + + return $segments; + } + + private function sortSegments($row1, $row2) + { + $customVarCategory = Piwik::translate('CustomVariables_CustomVariables'); + + $columns = array('type', 'category', 'name', 'segment'); + + foreach ($columns as $column) { + // Keep segments ordered alphabetically inside categories.. + $type = -1; + if ($column == 'name') $type = 1; + + $compare = $type * strcmp($row1[$column], $row2[$column]); + + // hack so that custom variables "page" are grouped together in the doc + if ($row1['category'] == $customVarCategory + && $row1['category'] == $row2['category'] + ) { + $compare = strcmp($row1['segment'], $row2['segment']); + return $compare; + } + + if ($compare != 0) { + return $compare; + } + } + + return $compare; + } + +} \ No newline at end of file diff --git a/plugins/API/WidgetMetadata.php b/plugins/API/WidgetMetadata.php new file mode 100644 index 0000000000..ef12800a39 --- /dev/null +++ b/plugins/API/WidgetMetadata.php @@ -0,0 +1,282 @@ +createMissingCategoriesAndSubcategories($categoryList, $widgetsList->getWidgetConfigs()); + + return $this->buildPagesMetadata($categoryList, $widgetsList); + } + + public function getWidgetMetadata(CategoryList $categoryList, WidgetsList $widgetsList) + { + $this->createMissingCategoriesAndSubcategories($categoryList, $widgetsList->getWidgetConfigs()); + + $flat = array(); + + foreach ($widgetsList->getWidgetConfigs() as $widgetConfig) { + + /** @var WidgetConfig[] $widgets */ + $widgets = array($widgetConfig); + if ($widgetConfig instanceof WidgetContainerConfig) { + // so far we go only one level down, in theory these widgetConfigs could have again containers containing configs + $widgets = array_merge($widgets, $widgetConfig->getWidgetConfigs()); + } + + foreach ($widgets as $widget) { + // make sure to include only widgetizable widgets + if (!$widget->isWidgetizeable() || !$widget->getName()) { + continue; + } + + $flat[] = $this->buildWidgetMetadata($widget, $categoryList); + } + } + + usort($flat, array($this, 'sortWidgets')); + + return $flat; + } + + /** + * @param WidgetConfig $widget + * @param CategoryList|null $categoryList If null, no category information will be added to the widgets in first + * level (they will be added to nested widgets as potentially needed eg for + * widgets in ByDimensionView where they are needed to build the left menu) + * @return array + */ + public function buildWidgetMetadata(WidgetConfig $widget, $categoryList = null) + { + $item = array( + 'name' => Piwik::translate($widget->getName()) + ); + + if (isset($categoryList)) { + $category = $categoryList->getCategory($widget->getCategoryId()); + $subcategory = $category ? $category->getSubcategory($widget->getSubcategoryId()) : null; + + $item['category'] = $this->buildCategoryMetadata($category); + $item['subcategory'] = $this->buildSubcategoryMetadata($subcategory); + } + + $item['module'] = $widget->getModule(); + $item['action'] = $widget->getAction(); + $item['order'] = $widget->getOrder(); + $item['parameters'] = $widget->getParameters(); + $item['uniqueId'] = $widget->getUniqueId(); + + $middleware = $widget->getMiddlewareParameters(); + + if (!empty($middleware)) { + $item['middlewareParameters'] = $middleware; + } + + if ($widget instanceof ReportWidgetConfig) { + $item['viewDataTable'] = $widget->getViewDataTable(); + $item['isReport'] = true; + } + + if ($widget instanceof WidgetContainerConfig) { + $item['layout'] = $widget->getLayout(); + $item['isContainer'] = true; + + // we do not want to create categories to the inital categoryList. Otherwise we'd maybe display more pages + // etc. + $subCategoryList = new CategoryList(); + $this->createMissingCategoriesAndSubcategories($subCategoryList, $widget->getWidgetConfigs()); + + $children = array(); + foreach ($widget->getWidgetConfigs() as $widgetConfig) { + $children[] = $this->buildWidgetMetadata($widgetConfig, $subCategoryList); + } + $item['widgets'] = $children; + } + + return $item; + } + + private function sortWidgets($widgetA, $widgetB) { + $orderA = $widgetA['category']['order']; + $orderB = $widgetB['category']['order']; + + if ($orderA === $orderB) { + if (!empty($widgetA['subcategory']['order']) && !empty($widgetB['subcategory']['order'])) { + + $subOrderA = $widgetA['subcategory']['order']; + $subOrderB = $widgetB['subcategory']['order']; + + if ($subOrderA === $subOrderB) { + return 0; + } + + return $subOrderA > $subOrderB ? 1 : -1; + + } elseif (!empty($orderA)) { + + return 1; + } + + return -1; + } + + return $orderA > $orderB ? 1 : -1; + } + + /** + * @param Category|null $category + * @return array + */ + private function buildCategoryMetadata($category) + { + if (!isset($category)) { + return null; + } + + return array( + 'id' => (string) $category->getId(), + 'name' => Piwik::translate($category->getId()), + 'order' => $category->getOrder(), + ); + } + + /** + * @param Subcategory|null $subcategory + * @return array + */ + private function buildSubcategoryMetadata($subcategory) + { + if (!isset($subcategory)) { + return null; + } + + return array( + 'id' => (string) $subcategory->getId(), + 'name' => Piwik::translate($subcategory->getName()), + 'order' => $subcategory->getOrder(), + ); + } + + /** + * @param CategoryList $categoryList + * @param WidgetConfig[] $widgetConfigs + */ + private function createMissingCategoriesAndSubcategories($categoryList, $widgetConfigs) + { + // move reports into categories/subcategories and create missing ones if needed + foreach ($widgetConfigs as $widgetConfig) { + $categoryId = $widgetConfig->getCategoryId(); + $subcategoryId = $widgetConfig->getSubcategoryId(); + + if (!$categoryId) { + continue; + } + + if ($widgetConfig instanceof WidgetContainerConfig && !$widgetConfig->getWidgetConfigs()) { + // if a container does not contain any widgets, ignore it + continue; + } + + if (!$categoryList->hasCategory($categoryId)) { + $categoryList->addCategory($this->createCategory($categoryId)); + } + + if (!$subcategoryId) { + continue; + } + + $category = $categoryList->getCategory($categoryId); + + if (!$category->hasSubcategory($subcategoryId)) { + $category->addSubcategory($this->createSubcategory($categoryId, $subcategoryId)); + } + } + } + + private function createCategory($categoryId) + { + $category = new Category(); + $category->setId($categoryId); + return $category; + } + + private function createSubcategory($categoryId, $subcategoryId) + { + $subcategory = new Subcategory(); + $subcategory->setCategoryId($categoryId); + $subcategory->setId($subcategoryId); + return $subcategory; + } + + /** + * @param CategoryList $categoryList + * @param WidgetsList $widgetsList + * @return array + */ + private function buildPagesMetadata(CategoryList $categoryList, WidgetsList $widgetsList) + { + $pages = array(); + + $widgets = array(); + foreach ($widgetsList->getWidgetConfigs() as $config) { + $pageId = $this->buildPageId($config->getCategoryId(), $config->getSubcategoryId()); + + if (!isset($widgets[$pageId])) { + $widgets[$pageId] = array(); + } + + $widgets[$pageId][] = $config; + } + + foreach ($categoryList->getCategories() as $category) { + foreach ($category->getSubcategories() as $subcategory) { + $pageId = $this->buildPageId($category->getId(), $subcategory->getId()); + + if (!empty($widgets[$pageId])) { + $pages[] = $this->buildPageMetadata($category, $subcategory, $widgets[$pageId]); + } + } + } + + return $pages; + } + + private function buildPageId($categoryId, $subcategoryId) + { + return $categoryId . '.' . $subcategoryId; + } + + public function buildPageMetadata(Category $category, Subcategory $subcategory, $widgetConfigs) + { + $ca = array( + 'uniqueId' => $this->buildPageId($category->getId(), $subcategory->getId()), + 'category' => $this->buildCategoryMetadata($category), + 'subcategory' => $this->buildSubcategoryMetadata($subcategory), + 'widgets' => array() + ); + + foreach ($widgetConfigs as $config) { + $ca['widgets'][] = $this->buildWidgetMetadata($config); + } + + return $ca; + } + +} \ No newline at end of file diff --git a/plugins/API/tests/Unit/WidgetMetadataTest.php b/plugins/API/tests/Unit/WidgetMetadataTest.php new file mode 100644 index 0000000000..bb4379a010 --- /dev/null +++ b/plugins/API/tests/Unit/WidgetMetadataTest.php @@ -0,0 +1,278 @@ +metadata = new WidgetMetadata(); + } + + public function test_buildWidgetMetadata_ShouldGenerateMetadata() + { + $config = $this->createWidgetConfig('Test', 'CategoryId', 'SubcategoryId'); + $list = $this->createCategoryList(array('CategoryId' => array('SubcategoryId'))); + $metadata = $this->metadata->buildWidgetMetadata($config, $list); + + $this->assertEquals(array( + 'name' => 'Test', + 'category' => array( + 'id' => 'CategoryId', + 'name' => 'CategoryId', + 'order' => 99, + ), + 'subcategory' => array( + 'id' => 'SubcategoryId', + 'name' => 'SubcategoryIdName', + 'order' => 99, + ), + 'module' => 'CoreHome', + 'action' => 'render', + 'order' => 99, + 'parameters' => array ( + 'module' => 'CoreHome', + 'action' => 'render' + ), + 'uniqueId' => 'widgetCoreHomerender' + ), $metadata); + } + + public function test_buildWidgetMetadata_ShouldSetCategoryAndSubcategoryToNull_IfBothGivenButNotExistInList() + { + $config = $this->createWidgetConfig('Test', 'CategoryId', 'SubcategoryId'); + $list = $this->createCategoryList(); + $metadata = $this->metadata->buildWidgetMetadata($config, $list); + + $this->assertNull($metadata['category']); + $this->assertNull($metadata['subcategory']); + } + + public function test_buildWidgetMetadata_ShouldSetSubcategoryToNull_IfCategoryGivenInListButSubcategoryNot() + { + $config = $this->createWidgetConfig('Test', 'CategoryId', 'SubcategoryId'); + $list = $this->createCategoryList(array('CategoryId' => array())); + $metadata = $this->metadata->buildWidgetMetadata($config, $list); + + $this->assertSame(array( + 'id' => 'CategoryId', + 'name' => 'CategoryId', + 'order' => 99, + ), $metadata['category']); + $this->assertNull($metadata['subcategory']); + } + + public function test_buildWidgetMetadata_ShouldNotAddCategoryAndSubcategoryToNull_IfNoCategoryListGiven() + { + $config = $this->createWidgetConfig('Test', 'CategoryId', 'SubcategoryId'); + $metadata = $this->metadata->buildWidgetMetadata($config); + + $this->assertArrayNotHasKey('category', $metadata); + $this->assertArrayNotHasKey('subcategory', $metadata); + } + + public function test_buildWidgetMetadata_ShouldAddOptionalMiddlewareParameters() + { + $config = $this->createWidgetConfig('Test', 'CategoryId', 'SubcategoryId'); + $config->setMiddlewareParameters(array('module' => 'Goals', 'action' => 'hasAnyConversions')); + $metadata = $this->metadata->buildWidgetMetadata($config); + + $this->assertSame(array('module' => 'Goals', 'action' => 'hasAnyConversions'), $metadata['middlewareParameters']); + } + + public function test_buildWidgetMetadata_ShouldAddReportInformtion_IfReportWidgetConfigGiven() + { + $config = new ReportWidgetConfig(); + $config->setDefaultViewDataTable('graph'); + $metadata = $this->metadata->buildWidgetMetadata($config); + + $this->assertSame('graph', $metadata['viewDataTable']); + $this->assertTrue($metadata['isReport']); + } + + public function test_buildWidgetMetadata_ShouldAddContainerInformtion_IfWidgetContainerConfigGiven() + { + $config = new WidgetContainerConfig(); + $config->setLayout('ByDimension'); + $config->addWidgetConfig($this->createWidgetConfig('NestedName1', 'NestedCategory1', 'NestedSubcategory1')); + $config->addWidgetConfig($this->createWidgetConfig('NestedName2', 'NestedCategory2', 'NestedSubcategory2')); + $metadata = $this->metadata->buildWidgetMetadata($config); + + $this->assertSame('ByDimension', $metadata['layout']); + $this->assertTrue($metadata['isContainer']); + $this->assertCount(2, $metadata['widgets']); + + $widget1 = $metadata['widgets'][0]; + $widget2 = $metadata['widgets'][1]; + $this->assertSame(array( + 'name' => 'NestedName1', + 'category' => array ( + 'id' => 'NestedCategory1', + 'name' => 'NestedCategory1', + 'order' => 99 + ), + 'subcategory' => array ( + 'id' => 'NestedSubcategory1', + 'name' => 'NestedSubcategory1', + 'order' => 99 + ), + 'module' => 'CoreHome', + 'action' => 'render', + 'order' => 99, + 'parameters' => array ( + 'module' => 'CoreHome', + 'action' => 'render', + ), + 'uniqueId' => 'widgetCoreHomerender' + ), $widget1); + $this->assertSame(array( + 'name' => 'NestedName2', + 'category' => array ( + 'id' => 'NestedCategory2', + 'name' => 'NestedCategory2', + 'order' => 99 + ), + 'subcategory' => array ( + 'id' => 'NestedSubcategory2', + 'name' => 'NestedSubcategory2', + 'order' => 99 + ), + 'module' => 'CoreHome', + 'action' => 'render', + 'order' => 99, + 'parameters' => array ( + 'module' => 'CoreHome', + 'action' => 'render', + ), + 'uniqueId' => 'widgetCoreHomerender' + ), $widget2); + } + + public function test_buildPageMetadata_ShouldAddContainerInformtion_IfWidgetContainerConfigGiven() + { + $config = new WidgetContainerConfig(); + $config->setLayout('ByDimension'); + + $widgets = array( + $this->createWidgetConfig('NestedName1', 'NestedCategory1', 'NestedSubcategory1'), + $this->createWidgetConfig('NestedName2', 'NestedCategory2', 'NestedSubcategory1'), + ); + + $category = $this->createCategory('NestedCategory1'); + $subcategory = $this->createSubcategory('NestedCategory1' ,'NestedSubcategory1'); + + $metadata = $this->metadata->buildPageMetadata($category, $subcategory, $widgets); + + $this->assertSame(array( + 'uniqueId' => 'NestedCategory1.NestedSubcategory1', + 'category' => array ( + 'id' => 'NestedCategory1', + 'name' => 'NestedCategory1', + 'order' => 99, + ), + 'subcategory' => array ( + 'id' => 'NestedSubcategory1', + 'name' => 'NestedSubcategory1Name', + 'order' => 99, + ), + 'widgets' => array ( + 0 => array ( // widgets should not have category / subcategory again, it's already present above + 'name' => 'NestedName1', + 'module' => 'CoreHome', + 'action' => 'render', + 'order' => 99, + 'parameters' => array ( + 'module' => 'CoreHome', + 'action' => 'render', + ), + 'uniqueId' => 'widgetCoreHomerender', + ), array ( + 'name' => 'NestedName2', + 'module' => 'CoreHome', + 'action' => 'render', + 'order' => 99, + 'parameters' => array ( + 'module' => 'CoreHome', + 'action' => 'render', + ), + 'uniqueId' => 'widgetCoreHomerender' + ) + ) + ), $metadata); + } + + private function createWidgetConfig($name, $categoryId, $subcategoryId = '') + { + $widgetConfig = new WidgetConfig(); + $widgetConfig->setName($name); + $widgetConfig->setCategoryId($categoryId); + $widgetConfig->setSubcategoryId($subcategoryId); + $widgetConfig->setModule('CoreHome'); + $widgetConfig->setAction('render'); + + return $widgetConfig; + } + + private function createCategoryList($categories = array()) + { + $list = new CategoryList(); + + foreach ($categories as $categoryId => $subcategoryIds) { + $category = $this->createCategory($categoryId); + $list->addCategory($category); + + foreach ($subcategoryIds as $subcategoryId) { + $subcategory = $this->createSubcategory($categoryId, $subcategoryId); + $category->addSubcategory($subcategory); + } + } + + return $list; + } + + private function createSubcategory($categoryId, $subcategoryId) + { + $subcategory = new Subcategory(); + $subcategory->setCategoryId($categoryId); + $subcategory->setId($subcategoryId); + $subcategory->setName($subcategoryId . 'Name'); + + return $subcategory; + } + + private function createCategory($categoryId) + { + $category = new Category(); + $category->setId($categoryId); + return $category; + } + +} diff --git a/plugins/Actions/API.php b/plugins/Actions/API.php index 891400e122..e475f4240c 100644 --- a/plugins/Actions/API.php +++ b/plugins/Actions/API.php @@ -22,6 +22,7 @@ use Piwik\Plugins\Actions\Columns\Metrics\BounceRate; use Piwik\Plugins\Actions\Columns\Metrics\ExitRate; use Piwik\Plugins\CustomVariables\API as APICustomVariables; use Piwik\Plugins\Actions\Actions\ActionSiteSearch; +use Piwik\Plugin\Reports; use Piwik\Tracker\Action; use Piwik\Tracker\PageUrl; @@ -55,7 +56,7 @@ class API extends \Piwik\Plugin\API { Piwik::checkUserHasViewAccess($idSite); - $report = Report::factory("Actions", "get"); + $report = Reports::factory("Actions", "get"); $archive = Archive::build($idSite, $period, $date, $segment); $requestedColumns = Piwik::getArrayFromApiParameter($columns); diff --git a/plugins/Actions/Actions.php b/plugins/Actions/Actions.php index 557e4c77b8..bca4396271 100644 --- a/plugins/Actions/Actions.php +++ b/plugins/Actions/Actions.php @@ -11,6 +11,7 @@ namespace Piwik\Plugins\Actions; use Piwik\ArchiveProcessor; use Piwik\Common; use Piwik\Db; +use Piwik\Plugins\CoreVisualizations\Visualizations\Sparklines; use Piwik\Site; use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable; diff --git a/plugins/Actions/Categories/DownloadsSubcategory.php b/plugins/Actions/Categories/DownloadsSubcategory.php new file mode 100644 index 0000000000..ac432b11d1 --- /dev/null +++ b/plugins/Actions/Categories/DownloadsSubcategory.php @@ -0,0 +1,19 @@ +pluginName, 'getSiteSearchKeywords'); - $noResult = Report::factory($this->pluginName, 'getSiteSearchNoResultKeywords'); - $pageUrls = Report::factory($this->pluginName, 'getPageUrlsFollowingSiteSearch'); - - $view->keywords = $keyword->render(); - $view->noResultKeywords = $noResult->render(); - $view->pagesUrlsFollowingSiteSearch = $pageUrls->render(); - - $categoryTrackingEnabled = Actions::isCustomVariablesPluginsEnabled(); - if ($categoryTrackingEnabled) { - $categories = Report::factory($this->pluginName, 'getSiteSearchCategories'); - $view->categories = $categories->render(); - } - - return $view->render(); - } - -} diff --git a/plugins/Actions/Menu.php b/plugins/Actions/Menu.php deleted file mode 100644 index 9a7424b4e9..0000000000 --- a/plugins/Actions/Menu.php +++ /dev/null @@ -1,29 +0,0 @@ -addActionsItem('', $this->urlForAction('menuGetPageUrls'), 15); - - $idSite = Common::getRequestVar('idSite', 0, 'int'); - $idSites = Common::getRequestVar('idSites', '', 'string'); - - $actions = new Actions(); - if ($actions->isSiteSearchEnabled($idSites, $idSite)) { - $menu->addActionsItem('Actions_SubmenuSitesearch', $this->urlForAction('indexSiteSearch'), 5); - } - } - -} diff --git a/plugins/Actions/Reports/Base.php b/plugins/Actions/Reports/Base.php index 45c9c0af9c..20e35593d8 100644 --- a/plugins/Actions/Reports/Base.php +++ b/plugins/Actions/Reports/Base.php @@ -21,7 +21,7 @@ abstract class Base extends \Piwik\Plugin\Report { protected function init() { - $this->category = 'General_Actions'; + $this->categoryId = 'General_Actions'; $this->processedMetrics = false; $this->recursiveLabelSeparator = '/'; } diff --git a/plugins/Actions/Reports/GetDownloads.php b/plugins/Actions/Reports/GetDownloads.php index f168cba878..92975b969e 100644 --- a/plugins/Actions/Reports/GetDownloads.php +++ b/plugins/Actions/Reports/GetDownloads.php @@ -26,8 +26,7 @@ class GetDownloads extends Base $this->actionToLoadSubTables = $this->action; $this->order = 9; - $this->menuTitle = 'General_Downloads'; - $this->widgetTitle = 'General_Downloads'; + $this->subcategoryId = 'General_Downloads'; } public function getMetrics() diff --git a/plugins/Actions/Reports/GetEntryPageTitles.php b/plugins/Actions/Reports/GetEntryPageTitles.php index 7c029f4b02..9df1d74450 100644 --- a/plugins/Actions/Reports/GetEntryPageTitles.php +++ b/plugins/Actions/Reports/GetEntryPageTitles.php @@ -15,6 +15,9 @@ use Piwik\Plugins\Actions\Columns\Metrics\AveragePageGenerationTime; use Piwik\Plugins\Actions\Columns\Metrics\AverageTimeOnPage; use Piwik\Plugins\Actions\Columns\Metrics\BounceRate; use Piwik\Plugins\Actions\Columns\Metrics\ExitRate; +use Piwik\Plugin\Reports; +use Piwik\Report\ReportWidgetFactory; +use Piwik\Widget\WidgetsList; class GetEntryPageTitles extends Base { @@ -35,8 +38,11 @@ class GetEntryPageTitles extends Base ); $this->order = 6; $this->actionToLoadSubTables = $this->action; + } - $this->widgetTitle = 'Actions_WidgetEntryPageTitles'; + public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory) + { + $widgetsList->addWidgetConfig($factory->createWidget()->setName('Actions_WidgetEntryPageTitles')); } public function getProcessedMetrics() @@ -79,8 +85,8 @@ class GetEntryPageTitles extends Base public function getRelatedReports() { return array( - self::factory('Actions', 'getPageTitles'), - self::factory('Actions', 'getEntryPageUrls') + Reports::factory('Actions', 'getPageTitles'), + Reports::factory('Actions', 'getEntryPageUrls') ); } } diff --git a/plugins/Actions/Reports/GetEntryPageUrls.php b/plugins/Actions/Reports/GetEntryPageUrls.php index f3795db099..c934c7ab10 100644 --- a/plugins/Actions/Reports/GetEntryPageUrls.php +++ b/plugins/Actions/Reports/GetEntryPageUrls.php @@ -17,6 +17,9 @@ use Piwik\Plugins\Actions\Columns\Metrics\AveragePageGenerationTime; use Piwik\Plugins\Actions\Columns\Metrics\AverageTimeOnPage; use Piwik\Plugins\Actions\Columns\Metrics\BounceRate; use Piwik\Plugins\Actions\Columns\Metrics\ExitRate; +use Piwik\Plugin\Reports; +use Piwik\Report\ReportWidgetFactory; +use Piwik\Widget\WidgetsList; class GetEntryPageUrls extends Base { @@ -40,8 +43,7 @@ class GetEntryPageUrls extends Base $this->actionToLoadSubTables = $this->action; - $this->menuTitle = 'Actions_SubmenuPagesEntry'; - $this->widgetTitle = 'Actions_WidgetPagesEntry'; + $this->subcategoryId = 'Actions_SubmenuPagesEntry'; } public function getProcessedMetrics() @@ -83,7 +85,7 @@ class GetEntryPageUrls extends Base public function getRelatedReports() { return array( - self::factory('Actions', 'getEntryPageTitles'), + Reports::factory('Actions', 'getEntryPageTitles'), ); } } diff --git a/plugins/Actions/Reports/GetExitPageTitles.php b/plugins/Actions/Reports/GetExitPageTitles.php index 6cc5b1f320..53f235209d 100644 --- a/plugins/Actions/Reports/GetExitPageTitles.php +++ b/plugins/Actions/Reports/GetExitPageTitles.php @@ -15,6 +15,9 @@ use Piwik\Plugins\Actions\Columns\Metrics\AveragePageGenerationTime; use Piwik\Plugins\Actions\Columns\Metrics\AverageTimeOnPage; use Piwik\Plugins\Actions\Columns\Metrics\BounceRate; use Piwik\Plugins\Actions\Columns\Metrics\ExitRate; +use Piwik\Plugin\Reports; +use Piwik\Report\ReportWidgetFactory; +use Piwik\Widget\WidgetsList; class GetExitPageTitles extends Base { @@ -37,8 +40,13 @@ class GetExitPageTitles extends Base $this->order = 7; $this->actionToLoadSubTables = $this->action; + } - $this->widgetTitle = 'Actions_WidgetExitPageTitles'; + public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory) + { + // we have to do it manually since it's only done automatically if a subcategoryId is specified, + // we do not set a subcategoryId since this report is not supposed to be shown in the UI + $widgetsList->addWidgetConfig($factory->createWidget()); } public function getProcessedMetrics() @@ -86,8 +94,8 @@ class GetExitPageTitles extends Base public function getRelatedReports() { return array( - self::factory('Actions', 'getPageTitles'), - self::factory('Actions', 'getExitPageUrls'), + Reports::factory('Actions', 'getPageTitles'), + Reports::factory('Actions', 'getExitPageUrls'), ); } } diff --git a/plugins/Actions/Reports/GetExitPageUrls.php b/plugins/Actions/Reports/GetExitPageUrls.php index 2ef5d7a957..f46ac478cd 100644 --- a/plugins/Actions/Reports/GetExitPageUrls.php +++ b/plugins/Actions/Reports/GetExitPageUrls.php @@ -17,6 +17,9 @@ use Piwik\Plugins\Actions\Columns\Metrics\AveragePageGenerationTime; use Piwik\Plugins\Actions\Columns\Metrics\AverageTimeOnPage; use Piwik\Plugins\Actions\Columns\Metrics\BounceRate; use Piwik\Plugins\Actions\Columns\Metrics\ExitRate; +use Piwik\Plugin\Reports; +use Piwik\Report\ReportWidgetFactory; +use Piwik\Widget\WidgetsList; class GetExitPageUrls extends Base { @@ -40,8 +43,7 @@ class GetExitPageUrls extends Base $this->order = 4; - $this->menuTitle = 'Actions_SubmenuPagesExit'; - $this->widgetTitle = 'Actions_WidgetPagesExit'; + $this->subcategoryId = 'Actions_SubmenuPagesExit'; } public function getProcessedMetrics() @@ -97,7 +99,7 @@ class GetExitPageUrls extends Base public function getRelatedReports() { return array( - self::factory('Actions', 'getExitPageTitles'), + Reports::factory('Actions', 'getExitPageTitles'), ); } diff --git a/plugins/Actions/Reports/GetOutlinks.php b/plugins/Actions/Reports/GetOutlinks.php index adf21c572c..fb5e13e831 100644 --- a/plugins/Actions/Reports/GetOutlinks.php +++ b/plugins/Actions/Reports/GetOutlinks.php @@ -29,8 +29,7 @@ class GetOutlinks extends Base $this->actionToLoadSubTables = $this->action; - $this->menuTitle = 'General_Outlinks'; - $this->widgetTitle = 'General_Outlinks'; + $this->subcategoryId = 'General_Outlinks'; } public function getMetrics() diff --git a/plugins/Actions/Reports/GetPageTitles.php b/plugins/Actions/Reports/GetPageTitles.php index 8f7e193f9b..0c70086611 100644 --- a/plugins/Actions/Reports/GetPageTitles.php +++ b/plugins/Actions/Reports/GetPageTitles.php @@ -17,6 +17,9 @@ use Piwik\Plugins\Actions\Columns\Metrics\AveragePageGenerationTime; use Piwik\Plugins\Actions\Columns\Metrics\AverageTimeOnPage; use Piwik\Plugins\Actions\Columns\Metrics\BounceRate; use Piwik\Plugins\Actions\Columns\Metrics\ExitRate; +use Piwik\Plugin\Reports; +use Piwik\Report\ReportWidgetFactory; +use Piwik\Widget\WidgetsList; class GetPageTitles extends Base { @@ -40,8 +43,7 @@ class GetPageTitles extends Base $this->actionToLoadSubTables = $this->action; - $this->menuTitle = 'Actions_SubmenuPageTitles'; - $this->widgetTitle = 'Actions_WidgetPageTitles'; + $this->subcategoryId = 'Actions_SubmenuPageTitles'; } public function getMetrics() @@ -81,8 +83,8 @@ class GetPageTitles extends Base public function getRelatedReports() { return array( - self::factory('Actions', 'getEntryPageTitles'), - self::factory('Actions', 'getExitPageTitles'), + Reports::factory('Actions', 'getEntryPageTitles'), + Reports::factory('Actions', 'getExitPageTitles'), ); } } diff --git a/plugins/Actions/Reports/GetPageTitlesFollowingSiteSearch.php b/plugins/Actions/Reports/GetPageTitlesFollowingSiteSearch.php index 657e88211d..3d50ba4f95 100644 --- a/plugins/Actions/Reports/GetPageTitlesFollowingSiteSearch.php +++ b/plugins/Actions/Reports/GetPageTitlesFollowingSiteSearch.php @@ -15,6 +15,7 @@ use Piwik\Plugins\Actions\Columns\Metrics\AveragePageGenerationTime; use Piwik\Plugins\Actions\Columns\Metrics\AverageTimeOnPage; use Piwik\Plugins\Actions\Columns\Metrics\BounceRate; use Piwik\Plugins\Actions\Columns\Metrics\ExitRate; +use Piwik\Plugin\Reports; class GetPageTitlesFollowingSiteSearch extends SiteSearchBase { @@ -32,7 +33,8 @@ class GetPageTitlesFollowingSiteSearch extends SiteSearchBase new AveragePageGenerationTime() ); $this->order = 19; - $this->widgetTitle = 'Actions_WidgetPageTitlesFollowingSearch'; + + $this->subcategoryId = 'Actions_SubmenuSitesearch'; } public function configureView(ViewDataTable $view) @@ -80,7 +82,7 @@ class GetPageTitlesFollowingSiteSearch extends SiteSearchBase public function getRelatedReports() { return array( - self::factory('Actions', 'getPageUrlsFollowingSiteSearch'), + Reports::factory('Actions', 'getPageUrlsFollowingSiteSearch'), ); } } diff --git a/plugins/Actions/Reports/GetPageUrls.php b/plugins/Actions/Reports/GetPageUrls.php index 0af899ef0e..2c850a5339 100644 --- a/plugins/Actions/Reports/GetPageUrls.php +++ b/plugins/Actions/Reports/GetPageUrls.php @@ -15,6 +15,8 @@ use Piwik\Plugins\Actions\Columns\Metrics\BounceRate; use Piwik\Plugins\Actions\Columns\PageUrl; use Piwik\Plugins\Actions\Columns\Metrics\ExitRate; use Piwik\Plugins\Actions\Columns\Metrics\AverageTimeOnPage; +use Piwik\Report\ReportWidgetFactory; +use Piwik\Widget\WidgetsList; class GetPageUrls extends Base { @@ -37,10 +39,13 @@ class GetPageUrls extends Base new AveragePageGenerationTime() ); - $this->segmentSql = 'log_visit.visit_entry_idaction_url'; + $this->segmentSql = 'log_visit.visit_entry_idaction_url'; + $this->subcategoryId = 'General_Pages'; + } - $this->menuTitle = 'General_Pages'; - $this->widgetTitle = 'General_Pages'; + public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory) + { + $widgetsList->addWidgetConfig($factory->createWidget()->setName($this->subcategoryId)); } public function getMetrics() diff --git a/plugins/Actions/Reports/GetPageUrlsFollowingSiteSearch.php b/plugins/Actions/Reports/GetPageUrlsFollowingSiteSearch.php index 2d8ba1a3a2..063d3855b5 100644 --- a/plugins/Actions/Reports/GetPageUrlsFollowingSiteSearch.php +++ b/plugins/Actions/Reports/GetPageUrlsFollowingSiteSearch.php @@ -11,6 +11,7 @@ namespace Piwik\Plugins\Actions\Reports; use Piwik\Piwik; use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\Actions\Columns\DestinationPage; +use Piwik\Plugin\Reports; class GetPageUrlsFollowingSiteSearch extends GetPageTitlesFollowingSiteSearch { @@ -20,8 +21,9 @@ class GetPageUrlsFollowingSiteSearch extends GetPageTitlesFollowingSiteSearch $this->dimension = new DestinationPage(); $this->name = Piwik::translate('Actions_WidgetPageUrlsFollowingSearch'); $this->documentation = Piwik::translate('Actions_SiteSearchFollowingPagesDoc') . '
' . Piwik::translate('General_UsePlusMinusIconsDocumentation'); - $this->order = 18; - $this->widgetTitle = 'Actions_WidgetPageUrlsFollowingSearch'; + $this->order = 16; + + $this->subcategoryId = 'Actions_SubmenuSitesearch'; } public function configureView(ViewDataTable $view) @@ -34,7 +36,7 @@ class GetPageUrlsFollowingSiteSearch extends GetPageTitlesFollowingSiteSearch public function getRelatedReports() { return array( - self::factory('Actions', 'getPageTitlesFollowingSiteSearch'), + Reports::factory('Actions', 'getPageTitlesFollowingSiteSearch'), ); } } diff --git a/plugins/Actions/Reports/GetSiteSearchCategories.php b/plugins/Actions/Reports/GetSiteSearchCategories.php index 6d41e3c334..5388ff9198 100644 --- a/plugins/Actions/Reports/GetSiteSearchCategories.php +++ b/plugins/Actions/Reports/GetSiteSearchCategories.php @@ -23,8 +23,9 @@ class GetSiteSearchCategories extends SiteSearchBase $this->name = Piwik::translate('Actions_WidgetSearchCategories'); $this->documentation = Piwik::translate('Actions_SiteSearchCategories1') . '
' . Piwik::translate('Actions_SiteSearchCategories2'); $this->metrics = array('nb_visits', 'nb_pages_per_search', 'exit_rate'); - $this->order = 17; - $this->widgetTitle = 'Actions_WidgetSearchCategories'; + $this->order = 20; + + $this->subcategoryId = 'Actions_SubmenuSitesearch'; } protected function isEnabledForIdSites($idSites, $idSite) diff --git a/plugins/Actions/Reports/GetSiteSearchKeywords.php b/plugins/Actions/Reports/GetSiteSearchKeywords.php index d88684cd15..dc4b5e2d16 100644 --- a/plugins/Actions/Reports/GetSiteSearchKeywords.php +++ b/plugins/Actions/Reports/GetSiteSearchKeywords.php @@ -33,7 +33,7 @@ class GetSiteSearchKeywords extends SiteSearchBase new AveragePageGenerationTime() ); $this->order = 15; - $this->widgetTitle = 'Actions_WidgetSearchKeywords'; + $this->subcategoryId = 'Actions_SubmenuSitesearch'; } public function getMetrics() diff --git a/plugins/Actions/Reports/GetSiteSearchNoResultKeywords.php b/plugins/Actions/Reports/GetSiteSearchNoResultKeywords.php index 94b19e8566..c1c01ca504 100644 --- a/plugins/Actions/Reports/GetSiteSearchNoResultKeywords.php +++ b/plugins/Actions/Reports/GetSiteSearchNoResultKeywords.php @@ -31,8 +31,9 @@ class GetSiteSearchNoResultKeywords extends SiteSearchBase new ExitRate(), new AveragePageGenerationTime() ); - $this->order = 16; - $this->widgetTitle = 'Actions_WidgetSearchNoResultKeywords'; + $this->order = 18; + + $this->subcategoryId = 'Actions_SubmenuSitesearch'; } public function getMetrics() diff --git a/plugins/Actions/Reports/SiteSearchBase.php b/plugins/Actions/Reports/SiteSearchBase.php index e30a2243d8..d4715e04e6 100644 --- a/plugins/Actions/Reports/SiteSearchBase.php +++ b/plugins/Actions/Reports/SiteSearchBase.php @@ -18,7 +18,7 @@ abstract class SiteSearchBase extends Base protected function init() { parent::init(); - $this->category = 'Actions_SubmenuSitesearch'; + $this->categoryId = 'General_Actions'; } public function isEnabled() diff --git a/plugins/Actions/templates/indexSiteSearch.twig b/plugins/Actions/templates/indexSiteSearch.twig deleted file mode 100644 index 8d9eaa0909..0000000000 --- a/plugins/Actions/templates/indexSiteSearch.twig +++ /dev/null @@ -1,21 +0,0 @@ -
- -
-

{{ 'Actions_WidgetSearchKeywords'|translate }}

- {{ keywords|raw }} - -

{{ 'Actions_WidgetSearchNoResultKeywords'|translate }}

- {{ noResultKeywords|raw }} - - {% if categories is defined %} -

{{ 'Actions_WidgetSearchCategories'|translate }}

- {{ categories|raw }} - {% endif %} -
- -
-

{{ 'Actions_WidgetPageUrlsFollowingSearch'|translate }}

- {{ pagesUrlsFollowingSiteSearch|raw }} -
- -
diff --git a/plugins/Contents/Categories/ContentsSubcategory.php b/plugins/Contents/Categories/ContentsSubcategory.php new file mode 100644 index 0000000000..735d376e4f --- /dev/null +++ b/plugins/Contents/Categories/ContentsSubcategory.php @@ -0,0 +1,19 @@ + 'addMetricTranslations', 'AssetManager.getJavaScriptFiles' => 'getJsFiles', - 'AssetManager.getStylesheetFiles' => 'getStylesheetFiles', + 'AssetManager.getStylesheetFiles' => 'getStylesheetFiles' ); } diff --git a/plugins/Contents/Controller.php b/plugins/Contents/Controller.php deleted file mode 100644 index a17ec3fdce..0000000000 --- a/plugins/Contents/Controller.php +++ /dev/null @@ -1,51 +0,0 @@ -pluginName, 'getContentNames'); - $contentPieces = Report::factory($this->pluginName, 'getContentPieces'); - $reports = array($contentNames, $contentPieces); - - foreach($reports as $report) { - $reportsView->addReport( - $report->getCategory(), - $report->getName(), - 'Contents.' . Report::PREFIX_ACTION_IN_MENU . ucfirst($report->getAction()) - ); - } - - return $reportsView->render(); - } - - public function menuGetContentNames() - { - $report = Report::factory($this->pluginName, 'getContentNames'); - - return View::singleReport($report->getName(), $report->render()); - } - - public function menuGetContentPieces() - { - $report = Report::factory($this->pluginName, 'getContentPieces'); - - return View::singleReport($report->getName(), $report->render()); - } - -} diff --git a/plugins/Contents/Menu.php b/plugins/Contents/Menu.php deleted file mode 100644 index 2e0d25bb7f..0000000000 --- a/plugins/Contents/Menu.php +++ /dev/null @@ -1,24 +0,0 @@ -addActionsItem('Contents_Contents', array('module' => 'Contents', 'action' => 'index'), $orderId = 40); - } -} diff --git a/plugins/Contents/Reports/Base.php b/plugins/Contents/Reports/Base.php index f07baf973d..e323bebdbe 100644 --- a/plugins/Contents/Reports/Base.php +++ b/plugins/Contents/Reports/Base.php @@ -8,18 +8,27 @@ */ namespace Piwik\Plugins\Contents\Reports; -use Piwik\Columns\Dimension; use Piwik\Common; use Piwik\Piwik; use Piwik\Plugin\Report; use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\Contents\Dimensions; +use Piwik\Report\ReportWidgetFactory; +use Piwik\Widget\WidgetsList; abstract class Base extends Report { protected function init() { - $this->category = 'General_Actions'; + $this->categoryId = 'General_Actions'; + $this->subcategoryId = 'Contents_Contents'; + } + + public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory) + { + $widget = $factory->createWidget(); + + $widgetsList->addToContainerWidget('Contents', $widget); } /** diff --git a/plugins/Contents/Reports/GetContentNames.php b/plugins/Contents/Reports/GetContentNames.php index d217af5d71..6afb8e071e 100644 --- a/plugins/Contents/Reports/GetContentNames.php +++ b/plugins/Contents/Reports/GetContentNames.php @@ -32,7 +32,6 @@ class GetContentNames extends Base $this->order = 35; $this->actionToLoadSubTables = 'getContentNames'; - $this->widgetTitle = 'Contents_ContentName'; $this->metrics = array('nb_impressions', 'nb_interactions'); $this->processedMetrics = array(new InteractionRate()); } diff --git a/plugins/Contents/Reports/GetContentPieces.php b/plugins/Contents/Reports/GetContentPieces.php index 7ab3f1ed1c..ede8da9405 100644 --- a/plugins/Contents/Reports/GetContentPieces.php +++ b/plugins/Contents/Reports/GetContentPieces.php @@ -32,8 +32,6 @@ class GetContentPieces extends Base $this->order = 36; $this->actionToLoadSubTables = 'getContentPieces'; - $this->widgetTitle = 'Contents_ContentPiece'; - $this->metrics = array('nb_impressions', 'nb_interactions'); $this->processedMetrics = array(new InteractionRate()); } diff --git a/plugins/Contents/Widgets/ContentsByDimension.php b/plugins/Contents/Widgets/ContentsByDimension.php new file mode 100644 index 0000000000..3f2291e8d8 --- /dev/null +++ b/plugins/Contents/Widgets/ContentsByDimension.php @@ -0,0 +1,21 @@ +January 3 – 9, 2010 Actions + Contents Content Name Contents getContentNames diff --git a/plugins/Contents/tests/System/expected/test_Contents_Contents.getContentPieces_lastN__API.getProcessedReport_day.xml b/plugins/Contents/tests/System/expected/test_Contents_Contents.getContentPieces_lastN__API.getProcessedReport_day.xml index b43860be63..f0115ea581 100644 --- a/plugins/Contents/tests/System/expected/test_Contents_Contents.getContentPieces_lastN__API.getProcessedReport_day.xml +++ b/plugins/Contents/tests/System/expected/test_Contents_Contents.getContentPieces_lastN__API.getProcessedReport_day.xml @@ -4,6 +4,7 @@ January 3 – 9, 2010 Actions + Contents Content Piece Contents getContentPieces diff --git a/plugins/CoreConsole/Commands/GenerateReport.php b/plugins/CoreConsole/Commands/GenerateReport.php index 9eb7313400..3f9fda4939 100644 --- a/plugins/CoreConsole/Commands/GenerateReport.php +++ b/plugins/CoreConsole/Commands/GenerateReport.php @@ -10,8 +10,10 @@ namespace Piwik\Plugins\CoreConsole\Commands; use Piwik\Columns\Dimension; +use Piwik\Piwik; use Piwik\Plugin\Manager; use Piwik\Plugin\Report; +use Piwik\Plugin\Reports; use Piwik\Translate; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; @@ -67,8 +69,8 @@ class GenerateReport extends GeneratePluginBase $this->copyTemplateToPlugin($exampleFolder, $pluginName, $replace, $whitelistFiles); $this->writeSuccessMessage($output, array( - sprintf('Reports/%s.php for %s generated.', ucfirst($apiName), $pluginName), - 'You should now implement the method called "' . lcfirst($apiName) . '" in API.php', + sprintf('plugins/%s/Reports/%s.php for %s generated.', $pluginName, ucfirst($apiName)), + 'You should now implement the method called "' . lcfirst($apiName) . '()" in API.php', // 'Read more about this here: link to developer guide', 'Enjoy!' )); @@ -78,8 +80,10 @@ class GenerateReport extends GeneratePluginBase { $order = 1; - foreach (Report::getAllReports() as $report) { - if ($report->getCategory() === $category) { + $reports = new Reports(); + + foreach ($reports->getAllReports() as $report) { + if ($report->getCategoryId() === $category) { if ($report->getOrder() > $order) { $order = $report->getOrder() + 1; } @@ -189,10 +193,12 @@ class GenerateReport extends GeneratePluginBase $category = $input->getOption('category'); + $reports = new Reports(); + $categories = array(); - foreach (Report::getAllReports() as $report) { - if ($report->getCategory()) { - $categories[] = $report->getCategory(); + foreach ($reports->getAllReports() as $report) { + if ($report->getCategoryId()) { + $categories[] = Piwik::translate($report->getCategoryId()); } } $categories = array_values(array_unique($categories)); @@ -226,7 +232,9 @@ class GenerateReport extends GeneratePluginBase $dimensions = array(); $dimensionNames = array(); - foreach (Report::getAllReports() as $report) { + $reports = new Reports(); + + foreach ($reports->getAllReports() as $report) { $dimension = $report->getDimension(); if (is_object($dimension)) { $name = $dimension->getName(); diff --git a/plugins/CoreConsole/Commands/GenerateWidget.php b/plugins/CoreConsole/Commands/GenerateWidget.php index da4f8e349d..05f92bd4af 100644 --- a/plugins/CoreConsole/Commands/GenerateWidget.php +++ b/plugins/CoreConsole/Commands/GenerateWidget.php @@ -10,8 +10,8 @@ namespace Piwik\Plugins\CoreConsole\Commands; use Piwik\Piwik; -use Piwik\Plugin\Widgets; use Piwik\Translate; +use Piwik\Widget\WidgetsList; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; @@ -25,6 +25,7 @@ class GenerateWidget extends GeneratePluginBase $this->setName('generate:widget') ->setDescription('Adds a plugin widget class to an existing plugin') ->addOption('pluginname', null, InputOption::VALUE_REQUIRED, 'The name of an existing plugin which does not have any widgets defined yet') + ->addOption('widgetname', null, InputOption::VALUE_REQUIRED, 'The name of the widget you want to create') ->addOption('category', null, InputOption::VALUE_REQUIRED, 'The name of the category the widget should belong to'); } @@ -33,6 +34,7 @@ class GenerateWidget extends GeneratePluginBase $pluginName = $this->getPluginName($input, $output); $this->checkAndUpdateRequiredPiwikVersion($pluginName, $output); + $widgetName = $this->getWidgetName($input, $output); $category = $this->getCategory($input, $output); if ($category === Piwik::translate($category)) { @@ -40,26 +42,78 @@ class GenerateWidget extends GeneratePluginBase $category = $this->makeTranslationIfPossible($pluginName, $category); } + $widgetMethod = $this->getWidgetMethodName($widgetName); + $widgetClass = ucfirst($widgetMethod); + $exampleFolder = PIWIK_INCLUDE_PATH . '/plugins/ExamplePlugin'; - $replace = array('ExamplePlugin' => $pluginName, - 'Example Category' => $category); - $whitelistFiles = array('/Widgets.php'); + $replace = array('ExamplePlugin' => $pluginName, + 'MyExampleWidget' => $widgetClass, + 'Example Widget Name' => $this->makeTranslationIfPossible($pluginName, $widgetName), + 'Example Widgets' => $category); + $whitelistFiles = array('/Widgets', '/Widgets/MyExampleWidget.php'); $this->copyTemplateToPlugin($exampleFolder, $pluginName, $replace, $whitelistFiles); $this->writeSuccessMessage($output, array( - sprintf('Widgets.php for %s generated.', $pluginName), - 'You can now start defining your plugin widgets', + sprintf('plugins/%s/Widgets/%s.php generated.', $pluginName, $widgetClass), + 'You can now start implementing the render() method.', 'Enjoy!' )); } + private function getWidgetMethodName($methodName) + { + $methodName = trim($methodName); + $methodName = str_replace(' ', '', $methodName); + $methodName = preg_replace("/[^A-Za-z0-9]/", '', $methodName); + + if (0 !== strpos(strtolower($methodName), 'get')) { + $methodName = 'get' . ucfirst($methodName); + } + + return lcfirst($methodName); + } + + /** + * @param InputInterface $input + * @param OutputInterface $output + * @return array + * @throws \RuntimeException + */ + protected function getWidgetName(InputInterface $input, OutputInterface $output) + { + $validate = function ($widgetName) { + if (empty($widgetName)) { + throw new \InvalidArgumentException('Please enter the name of your widget'); + } + + if (preg_match("/[^A-Za-z0-9 ]/", $widgetName)) { + throw new \InvalidArgumentException('Only alpha numerical characters and whitespaces are allowed'); + } + + return $widgetName; + }; + + $widgetName = $input->getOption('widgetname'); + + if (empty($widgetName)) { + $dialog = $this->getHelperSet()->get('dialog'); + $widgetName = $dialog->askAndValidate($output, 'Enter the name of your Widget, for instance "Browser Families": ', $validate); + } else { + $validate($widgetName); + } + + $widgetName = ucfirst($widgetName); + + return $widgetName; + } + protected function getExistingCategories() { $categories = array(); - foreach (Widgets::getAllWidgets() as $widget) { - if ($widget->getCategory()) { - $categories[] = Piwik::translate($widget->getCategory()); + foreach (WidgetsList::get()->getWidgetConfigs() as $widget) { + if ($widget->getCategoryId()) { + $categories[] = Piwik::translate($widget->getCategoryId()); } } $categories = array_values(array_unique($categories)); @@ -111,8 +165,8 @@ class GenerateWidget extends GeneratePluginBase */ protected function getPluginName(InputInterface $input, OutputInterface $output) { - $pluginNames = $this->getPluginNamesHavingNotSpecificFile('Widgets.php'); - $invalidName = 'You have to enter the name of an existing plugin which does not already have any widgets defined'; + $pluginNames = $this->getPluginNames(); + $invalidName = 'You have to enter a name of an existing plugin.'; return $this->askPluginNameAndValidate($input, $output, $pluginNames, $invalidName); } diff --git a/plugins/CoreHome/Categories/ActionsCategory.php b/plugins/CoreHome/Categories/ActionsCategory.php new file mode 100644 index 0000000000..e995df110d --- /dev/null +++ b/plugins/CoreHome/Categories/ActionsCategory.php @@ -0,0 +1,17 @@ +getPrettyTimeFromSeconds($value); + return $formatter->getPrettyTimeFromSeconds($value, true); } public function getTranslatedName() diff --git a/plugins/CoreHome/Controller.php b/plugins/CoreHome/Controller.php index a61419e5fb..a0866c0ff2 100644 --- a/plugins/CoreHome/Controller.php +++ b/plugins/CoreHome/Controller.php @@ -11,12 +11,13 @@ namespace Piwik\Plugins\CoreHome; use Exception; use Piwik\API\Request; use Piwik\Common; +use Piwik\DataTable\Renderer\Json; use Piwik\Date; use Piwik\FrontController; -use Piwik\Menu\MenuReporting; use Piwik\Notification\Manager as NotificationManager; use Piwik\Piwik; use Piwik\Plugin\Report; +use Piwik\Widget\Widget; use Piwik\Plugins\CoreHome\DataTableRowAction\MultiRowEvolution; use Piwik\Plugins\CoreHome\DataTableRowAction\RowEvolution; use Piwik\Plugins\CorePluginsAdmin\MarketplaceApiClient; @@ -28,7 +29,6 @@ use Piwik\UpdateCheck; use Piwik\Url; use Piwik\View; use Piwik\ViewDataTable\Manager as ViewDataTableManager; -use Piwik\Plugin\Widgets as PluginWidgets; class Controller extends \Piwik\Plugin\Controller { @@ -49,40 +49,38 @@ class Controller extends \Piwik\Plugin\Controller return 'redirectToCoreHomeIndex'; } - public function renderReportMenu(Report $report) + public function renderReportWidget(Report $report) { Piwik::checkUserHasSomeViewAccess(); $this->checkSitePermission(); $report->checkIsEnabled(); - $menuTitle = $report->getMenuTitle(); - - if (empty($menuTitle)) { - throw new Exception('This report is not supposed to be displayed in the menu, please define a $menuTitle in your report.'); - } - - $menuTitle = $this->translator->translate($menuTitle); - $content = $this->renderReportWidget($report); - - return View::singleReport($menuTitle, $content); + return $report->render(); } - public function renderReportWidget(Report $report) + public function renderWidgetContainer() { Piwik::checkUserHasSomeViewAccess(); $this->checkSitePermission(); - $report->checkIsEnabled(); + $view = new View('@CoreHome/widgetContainer'); + $view->isWidgetized = (bool) Common::getRequestVar('widget', 0, 'int'); + $view->containerId = Common::getRequestVar('containerId', null, 'string'); - return $report->render(); + return $view->render(); } - public function renderWidget(PluginWidgets $widget, $method) + /** + * @param Widget $widget + * @return mixed + * @throws Exception + */ + public function renderWidget($widget) { Piwik::checkUserHasSomeViewAccess(); - return $widget->$method(); + return $widget->render(); } function redirectToCoreHomeIndex() @@ -133,7 +131,6 @@ class Controller extends \Piwik\Plugin\Controller { $view = new View('@CoreHome/getDefaultIndexView'); $this->setGeneralVariablesView($view); - $view->menu = MenuReporting::getInstance()->getMenu(); $view->dashboardSettingsControl = new DashboardManagerControl(); $view->content = ''; return $view; diff --git a/plugins/CoreHome/CoreHome.php b/plugins/CoreHome/CoreHome.php index 23da8326aa..c8b2b428d0 100644 --- a/plugins/CoreHome/CoreHome.php +++ b/plugins/CoreHome/CoreHome.php @@ -13,6 +13,13 @@ namespace Piwik\Plugins\CoreHome; */ class CoreHome extends \Piwik\Plugin { + /** + * Defines a widget container layout that will display all widgets within a container inside a "tab" menu + * where on the left side a link is shown for each widget and on the right side the selected widget. + * @api + */ + const WIDGET_CONTAINER_LAYOUT_BY_DIMENSION = 'ByDimension'; + /** * @see Piwik\Plugin::registerEvents */ @@ -105,8 +112,6 @@ class CoreHome extends \Piwik\Plugin $jsFiles[] = "plugins/CoreHome/javascripts/dataTable_rowactions.js"; $jsFiles[] = "plugins/CoreHome/javascripts/popover.js"; $jsFiles[] = "plugins/CoreHome/javascripts/broadcast.js"; - $jsFiles[] = "plugins/CoreHome/javascripts/menu.js"; - $jsFiles[] = "plugins/CoreHome/javascripts/menu_init.js"; $jsFiles[] = "plugins/CoreHome/javascripts/calendar.js"; $jsFiles[] = "plugins/CoreHome/javascripts/sparkline.js"; $jsFiles[] = "plugins/CoreHome/javascripts/corehome.js"; @@ -120,8 +125,12 @@ class CoreHome extends \Piwik\Plugin $jsFiles[] = "plugins/CoreHome/angularjs/piwikApp.config.js"; $jsFiles[] = "plugins/CoreHome/angularjs/common/services/service.module.js"; + $jsFiles[] = "plugins/CoreHome/angularjs/common/services/global-ajax-queue.js"; $jsFiles[] = "plugins/CoreHome/angularjs/common/services/piwik.js"; $jsFiles[] = "plugins/CoreHome/angularjs/common/services/piwik-api.js"; + $jsFiles[] = "plugins/CoreHome/angularjs/common/services/piwik-url.js"; + $jsFiles[] = "plugins/CoreHome/angularjs/common/services/report-metadata-model.js"; + $jsFiles[] = "plugins/CoreHome/angularjs/common/services/reporting-pages-model.js"; $jsFiles[] = "plugins/CoreHome/angularjs/common/filters/filter.module.js"; $jsFiles[] = "plugins/CoreHome/angularjs/common/filters/translate.js"; @@ -130,6 +139,7 @@ class CoreHome extends \Piwik\Plugin $jsFiles[] = "plugins/CoreHome/angularjs/common/filters/length.js"; $jsFiles[] = "plugins/CoreHome/angularjs/common/filters/trim.js"; $jsFiles[] = "plugins/CoreHome/angularjs/common/filters/pretty-url.js"; + $jsFiles[] = "plugins/CoreHome/angularjs/common/filters/escape.js"; $jsFiles[] = "plugins/CoreHome/angularjs/common/directives/directive.module.js"; $jsFiles[] = "plugins/CoreHome/angularjs/common/directives/autocomplete-matched.js"; @@ -146,6 +156,8 @@ class CoreHome extends \Piwik\Plugin $jsFiles[] = "plugins/CoreHome/angularjs/history/history.service.js"; + $jsFiles[] = "plugins/CoreHome/angularjs/activity-indicator/activityindicator.directive.js"; + $jsFiles[] = "plugins/CoreHome/angularjs/siteselector/siteselector-model.service.js"; $jsFiles[] = "plugins/CoreHome/angularjs/siteselector/siteselector.controller.js"; $jsFiles[] = "plugins/CoreHome/angularjs/siteselector/siteselector.directive.js"; @@ -163,6 +175,21 @@ class CoreHome extends \Piwik\Plugin $jsFiles[] = "plugins/CoreHome/angularjs/ajax-form/ajax-form.controller.js"; $jsFiles[] = "plugins/CoreHome/angularjs/ajax-form/ajax-form.directive.js"; + + $jsFiles[] = "plugins/CoreHome/angularjs/widget-loader/widgetloader.directive.js"; + $jsFiles[] = "plugins/CoreHome/angularjs/widget-bydimension-container/widget-bydimension-container.directive.js"; + $jsFiles[] = "plugins/CoreHome/angularjs/widget-container/widgetcontainer.directive.js"; + $jsFiles[] = "plugins/CoreHome/angularjs/widget/widget.directive.js"; + + $jsFiles[] = "plugins/CoreHome/angularjs/popover-handler/popover-handler.directive.js"; + + $jsFiles[] = "plugins/CoreHome/angularjs/reporting-page/reportingpage.controller.js"; + $jsFiles[] = "plugins/CoreHome/angularjs/reporting-page/reportingpage-model.js"; + $jsFiles[] = "plugins/CoreHome/angularjs/reporting-page/reportingpage.directive.js"; + + $jsFiles[] = "plugins/CoreHome/angularjs/reporting-menu/reportingmenu.controller.js"; + $jsFiles[] = "plugins/CoreHome/angularjs/reporting-menu/reportingmenu-model.js"; + $jsFiles[] = "plugins/CoreHome/angularjs/reporting-menu/reportingmenu.directive.js"; } public function getClientSideTranslationKeys(&$translationKeys) @@ -258,5 +285,6 @@ class CoreHome extends \Piwik\Plugin $translationKeys[] = 'CoreHome_UndoPivotBySubtable'; $translationKeys[] = 'CoreHome_PivotBySubtable'; $translationKeys[] = 'General_LearnMore'; + $translationKeys[] = 'CoreHome_NoSuchPage'; } } diff --git a/plugins/CoreHome/Widgets.php b/plugins/CoreHome/Widgets.php deleted file mode 100644 index 17d888bd35..0000000000 --- a/plugins/CoreHome/Widgets.php +++ /dev/null @@ -1,63 +0,0 @@ -translator = $translator; - } - - protected function init() - { - $this->addWidget('CoreHome_SupportPiwik', 'getDonateForm'); - $this->addWidget('Installation_Welcome', 'getPromoVideo'); - } - - /** - * Renders and echo's the in-app donate form w/ slider. - */ - public function getDonateForm() - { - $view = new View('@CoreHome/getDonateForm'); - - if (Common::getRequestVar('widget', false) - && Piwik::hasUserSuperUserAccess()) { - $view->footerMessage = $this->translator->translate('CoreHome_OnlyForSuperUserAccess'); - } - - return $view->render(); - } - - /** - * Renders and echo's HTML that displays the Piwik promo video. - */ - public function getPromoVideo() - { - $view = new View('@CoreHome/getPromoVideo'); - $view->shareText = $this->translator->translate('CoreHome_SharePiwikShort'); - $view->shareTextLong = $this->translator->translate('CoreHome_SharePiwikLong'); - $view->promoVideoUrl = 'https://www.youtube.com/watch?v=OslfF_EH81g'; - - return $view->render(); - } -} diff --git a/plugins/CoreHome/Widgets/GetDonateForm.php b/plugins/CoreHome/Widgets/GetDonateForm.php new file mode 100644 index 0000000000..093fe8c3a2 --- /dev/null +++ b/plugins/CoreHome/Widgets/GetDonateForm.php @@ -0,0 +1,48 @@ +translator = $translator; + } + + public static function configure(WidgetConfig $config) + { + $config->setCategoryId('Example Widgets'); + $config->setName('CoreHome_SupportPiwik'); + $config->setOrder(5); + } + + public function render() + { + $view = new View('@CoreHome/getDonateForm'); + + if (Common::getRequestVar('widget', false) + && Piwik::hasUserSuperUserAccess()) { + $view->footerMessage = $this->translator->translate('CoreHome_OnlyForSuperUserAccess'); + } + + return $view->render(); + } +} \ No newline at end of file diff --git a/plugins/CoreHome/Widgets/GetPromoVideo.php b/plugins/CoreHome/Widgets/GetPromoVideo.php new file mode 100644 index 0000000000..49636b5e0e --- /dev/null +++ b/plugins/CoreHome/Widgets/GetPromoVideo.php @@ -0,0 +1,44 @@ +translator = $translator; + } + + public static function configure(WidgetConfig $config) + { + $config->setCategoryId('Example Widgets'); + $config->setName('Installation_Welcome'); + $config->setOrder(10); + } + + public function render() + { + $view = new View('@CoreHome/getPromoVideo'); + $view->shareText = $this->translator->translate('CoreHome_SharePiwikShort'); + $view->shareTextLong = $this->translator->translate('CoreHome_SharePiwikLong'); + $view->promoVideoUrl = 'https://www.youtube.com/watch?v=OslfF_EH81g'; + + return $view->render(); + } +} \ No newline at end of file diff --git a/plugins/CoreHome/angularjs/activity-indicator/activityindicator.directive.js b/plugins/CoreHome/angularjs/activity-indicator/activityindicator.directive.js new file mode 100644 index 0000000000..4417cea7ac --- /dev/null +++ b/plugins/CoreHome/angularjs/activity-indicator/activityindicator.directive.js @@ -0,0 +1,31 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +/** + * Shows a general loading message while [loading] is set to true. + * + * @param {Boolean} loading If true, the activity indicator is shown, otherwise the indicator is hidden. + * + * Example: + *
+ */ +(function () { + angular.module('piwikApp').directive('piwikActivityIndicator', piwikActivityIndicator); + + piwikActivityIndicator.$inject = ['piwik']; + + function piwikActivityIndicator(piwik){ + return { + restrict: 'A', + transclude: true, + scope: { + loading: '=' + }, + templateUrl: 'plugins/CoreHome/angularjs/activity-indicator/activityindicator.html?cb=' + piwik.cacheBuster + }; + } +})(); \ No newline at end of file diff --git a/plugins/CoreHome/angularjs/activity-indicator/activityindicator.html b/plugins/CoreHome/angularjs/activity-indicator/activityindicator.html new file mode 100644 index 0000000000..f6080ae817 --- /dev/null +++ b/plugins/CoreHome/angularjs/activity-indicator/activityindicator.html @@ -0,0 +1,3 @@ +
+ {{ 'General_LoadingData'|translate }} +
\ No newline at end of file diff --git a/plugins/CoreHome/angularjs/ajax-form/ajax-form.directive.js b/plugins/CoreHome/angularjs/ajax-form/ajax-form.directive.js index 89d572cedf..2eef346ec6 100644 --- a/plugins/CoreHome/angularjs/ajax-form/ajax-form.directive.js +++ b/plugins/CoreHome/angularjs/ajax-form/ajax-form.directive.js @@ -132,7 +132,9 @@ scope.ajaxForm.data[name] = val; if (!skipScopeApply) { - scope.$apply(); + setTimeout(function () { + scope.$apply(); + }, 0); } } }; diff --git a/plugins/CoreHome/angularjs/common/directives/focus-anywhere-but-here.js b/plugins/CoreHome/angularjs/common/directives/focus-anywhere-but-here.js index 0617c5df88..ee1a2cf219 100644 --- a/plugins/CoreHome/angularjs/common/directives/focus-anywhere-but-here.js +++ b/plugins/CoreHome/angularjs/common/directives/focus-anywhere-but-here.js @@ -24,13 +24,17 @@ function onClickOutsideElement (event) { if (element.has(event.target).length === 0) { - scope.$apply(attr.piwikFocusAnywhereButHere); + setTimeout(function () { + scope.$apply(attr.piwikFocusAnywhereButHere); + }, 0); } } function onEscapeHandler (event) { if (event.which === 27) { - scope.$apply(attr.piwikFocusAnywhereButHere); + setTimeout(function () { + scope.$apply(attr.piwikFocusAnywhereButHere); + }, 0); } } diff --git a/plugins/CoreHome/angularjs/common/filters/escape.js b/plugins/CoreHome/angularjs/common/filters/escape.js new file mode 100644 index 0000000000..382e84b5ac --- /dev/null +++ b/plugins/CoreHome/angularjs/common/filters/escape.js @@ -0,0 +1,16 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ +(function () { + angular.module('piwikApp.filter').filter('escape', escape); + + function escape() { + + return function(value) { + return piwikHelper.escape(piwikHelper.htmlEntities(value)); + }; + } +})(); \ No newline at end of file diff --git a/plugins/CoreHome/angularjs/common/services/global-ajax-queue.js b/plugins/CoreHome/angularjs/common/services/global-ajax-queue.js new file mode 100644 index 0000000000..f831995810 --- /dev/null +++ b/plugins/CoreHome/angularjs/common/services/global-ajax-queue.js @@ -0,0 +1,14 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ +(function () { + angular.module('piwikApp.service').service('globalAjaxQueue', ajaxQueue); + + function ajaxQueue() { + + return globalAjaxQueue; + } +})(); \ No newline at end of file diff --git a/plugins/CoreHome/angularjs/common/services/piwik-url.js b/plugins/CoreHome/angularjs/common/services/piwik-url.js new file mode 100644 index 0000000000..f2d6e9bb0c --- /dev/null +++ b/plugins/CoreHome/angularjs/common/services/piwik-url.js @@ -0,0 +1,54 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ +(function () { + angular.module('piwikApp.service').service('piwikUrl', piwikUrl); + + piwikUrl.$inject = ['$location', 'piwik']; + + /** + * Similar to angulars $location but works around some limitation. Use it if you need to access search params + */ + function piwikUrl($location, piwik) { + + var model = { + getSearchParam: getSearchParam + } + + return model; + + function getSearchParam(paramName) + { + if (paramName === 'segment') { + var hash = window.location.href.split('#'); + if (hash && hash[1]) { + return piwik.broadcast.getValueFromHash(paramName, hash[1]); + } + + return broadcast.getValueFromUrl(paramName); + } + + // available in global scope + var search = $location.search(); + + if (!search[paramName]) { + // see https://github.com/angular/angular.js/issues/7239 (issue is resolved but problem still exists) + search[paramName] = piwik.broadcast.getValueFromUrl(paramName); + } + + if (search[paramName]) { + var value = search[paramName]; + + if (angular.isArray(search[paramName])) { + // use last one. Eg when having period=day&period=year angular would otherwise return ['day', 'year'] + return value[value.length - 1]; + } + + return value; + } + } + } +})(); \ No newline at end of file diff --git a/plugins/CoreHome/angularjs/common/services/report-metadata-model.js b/plugins/CoreHome/angularjs/common/services/report-metadata-model.js new file mode 100644 index 0000000000..f158861423 --- /dev/null +++ b/plugins/CoreHome/angularjs/common/services/report-metadata-model.js @@ -0,0 +1,52 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ +(function () { + angular.module('piwikApp.service').factory('reportMetadataModel', reportMetadataModel); + + reportMetadataModel.$inject = ['piwik', 'piwikApi']; + + function reportMetadataModel (piwik, piwikApi) { + + var reportsPromise = null; + + var model = { + reports: [], + fetchReportMetadata: fetchReportMetadata, + findReport: findReport + }; + + return model; + + function findReport(module, action) + { + var found = []; + + angular.forEach(model.reports, function (report) { + if (report.module === module && report.action === action) { + found = report; + } + }); + + return found; + } + + function fetchReportMetadata() + { + if (!reportsPromise) { + reportsPromise = piwikApi.fetch({ + method: 'API.getReportMetadata', + idSites: piwik.idSite || piwik.broadcast.getValueFromUrl('idSite'), + }).then(function (response) { + model.reports = response; + return response; + }); + } + + return reportsPromise; + } + } +})(); \ No newline at end of file diff --git a/plugins/CoreHome/angularjs/common/services/reporting-pages-model.js b/plugins/CoreHome/angularjs/common/services/reporting-pages-model.js new file mode 100644 index 0000000000..1b1e406c95 --- /dev/null +++ b/plugins/CoreHome/angularjs/common/services/reporting-pages-model.js @@ -0,0 +1,58 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ +(function () { + angular.module('piwikApp.service').factory('reportingPagesModel', reportingPagesModelService); + + reportingPagesModelService.$inject = ['piwikApi']; + + function reportingPagesModelService (piwikApi) { + var fetchAllPagesPromise = false; + + // those sites are going to be displayed + var model = { + pages : [], + findPage: findPage, + reloadAllPages : reloadAllPages, + getAllPages : getAllPages + }; + + return model; + + function findPage(categoryId, subcategoryId) + { + var found = null; + + angular.forEach(model.pages, function (page) { + if (page && + page.category && page.subcategory && + page.category.id === categoryId && ('' + page.subcategory.id) === subcategoryId) { + found = page; + } + }); + + return found; + } + + function reloadAllPages() + { + fetchAllPagesPromise = null; + return getAllPages(); + } + + function getAllPages() + { + if (!fetchAllPagesPromise) { + fetchAllPagesPromise = piwikApi.fetch({method: 'API.getReportPagesMetadata'}).then(function (response) { + model.pages = response; + return response; + }); + } + + return fetchAllPagesPromise; + } + } +})(); \ No newline at end of file diff --git a/plugins/CoreHome/angularjs/history/history.service.js b/plugins/CoreHome/angularjs/history/history.service.js index 2c6486a517..7dadf35ad0 100644 --- a/plugins/CoreHome/angularjs/history/history.service.js +++ b/plugins/CoreHome/angularjs/history/history.service.js @@ -36,6 +36,19 @@ loadCurrentPage(); } + function cleanHash(hash) + { + var chars = ['#', '/', '?']; + for (var i = 0; i != chars.length; ++i) { + var charToRemove = chars[i]; + if (hash.charAt(0) == charToRemove) { + hash = hash.substring(1); + } + } + + return hash; + } + // currently, the AJAX content URL is stored in $location.search(), but before it was stored in $location.path(). // this function makes sure URLs like http://piwik.net/?...#/module=Whatever&action=whatever still work. function changePathToSearch() { @@ -82,13 +95,7 @@ function load(hash) { // make sure the hash is just the query parameter values, w/o a starting #, / or ? char. broadcast.pageload & $location.path should get neither - var chars = ['#', '/', '?']; - for (var i = 0; i != chars.length; ++i) { - var charToRemove = chars[i]; - if (hash.charAt(0) == charToRemove) { - hash = hash.substring(1); - } - } + hash = cleanHash(hash); if (location.hash === '#?' + hash) { loadCurrentPage(); // it would not trigger a location change success event as URL is the same, call it manually diff --git a/plugins/CoreHome/angularjs/http404check.js b/plugins/CoreHome/angularjs/http404check.js index f2e2a86edf..5b720c9472 100644 --- a/plugins/CoreHome/angularjs/http404check.js +++ b/plugins/CoreHome/angularjs/http404check.js @@ -1,9 +1,9 @@ (function () { angular.module('piwikApp').factory('http404CheckInterceptor', http404CheckInterceptor); - http404CheckInterceptor.$inject = ['$q']; + http404CheckInterceptor.$inject = ['$q', 'globalAjaxQueue']; - function http404CheckInterceptor($q) { + function http404CheckInterceptor($q, globalAjaxQueue) { function isClientError(rejection) { @@ -15,8 +15,8 @@ } return { - 'responseError': function(rejection) { + if (rejection && isClientError(rejection) && rejection.config && diff --git a/plugins/CoreHome/angularjs/menudropdown/menudropdown.directive.html b/plugins/CoreHome/angularjs/menudropdown/menudropdown.directive.html index d1964d1ac4..14191ac20e 100644 --- a/plugins/CoreHome/angularjs/menudropdown/menudropdown.directive.html +++ b/plugins/CoreHome/angularjs/menudropdown/menudropdown.directive.html @@ -23,7 +23,7 @@ class="reset" src="plugins/CoreHome/images/reset_search.png"/> -
+
diff --git a/plugins/CoreHome/angularjs/menudropdown/menudropdown.directive.js b/plugins/CoreHome/angularjs/menudropdown/menudropdown.directive.js index 00fbf87d7b..313ef00d6c 100644 --- a/plugins/CoreHome/angularjs/menudropdown/menudropdown.directive.js +++ b/plugins/CoreHome/angularjs/menudropdown/menudropdown.directive.js @@ -34,10 +34,10 @@ templateUrl: 'plugins/CoreHome/angularjs/menudropdown/menudropdown.directive.html?cb=' + piwik.cacheBuster, link: function(scope, element, attrs) { - element.find('.item').on('click', function () { - var $self = angular.element(this); + scope.selectItem = function (event) { + var $self = angular.element(event.target); - if ($self.hasClass('disabled') || $self.hasClass('separator')) { + if (!$self.hasClass('item') || $self.hasClass('disabled') || $self.hasClass('separator')) { return; } @@ -47,11 +47,14 @@ }); } scope.$eval('view.showItems = false'); - scope.$apply(); + + setTimeout(function () { + scope.$apply(); + }, 0); element.find('.item').removeClass('active'); $self.addClass('active'); - }); + }; scope.searchItems = function (searchTerm) { diff --git a/plugins/CoreHome/angularjs/popover-handler/popover-handler.directive.js b/plugins/CoreHome/angularjs/popover-handler/popover-handler.directive.js new file mode 100644 index 0000000000..ea15f025b0 --- /dev/null +++ b/plugins/CoreHome/angularjs/popover-handler/popover-handler.directive.js @@ -0,0 +1,74 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +/** + * When present in the page it listens to a popover URL parameter. + * + * If present it will try to load the related content in a popover or if the URL is empty it will close an + * opened popover. + * + * Example: + *
+ */ +(function () { + angular.module('piwikApp').directive('piwikPopoverHandler', piwikPopoverHandler); + + piwikPopoverHandler.$inject = ['$location', '$rootScope', 'piwik']; + + function piwikPopoverHandler($location, $rootScope, piwik){ + + return { + restrict: 'A', + scope: {}, + controller: function () { + + function close() + { + Piwik_Popover.close(); + } + + function open(popoverParam) + { + // in case the $ was encoded (e.g. when using copy&paste on urls in some browsers) + popoverParam = decodeURIComponent(popoverParam); + // revert special encoding from broadcast.propagateNewPopoverParameter() + popoverParam = popoverParam.replace(/\$/g, '%'); + popoverParam = decodeURIComponent(popoverParam); + + var popoverParamParts = popoverParam.split(':'); + var handlerName = popoverParamParts[0]; + popoverParamParts.shift(); + var param = popoverParamParts.join(':'); + if (typeof piwik.broadcast.popoverHandlers[handlerName] != 'undefined' + && !piwik.broadcast.isLoginPage()) { + piwik.broadcast.popoverHandlers[handlerName](param); + } + } + + function openOrClose() + { + // should be rather done by routing + var popoverParam = $location.search().popover; + if (popoverParam) { + open(popoverParam); + } else { + close(); + } + } + + $rootScope.$on('$locationChangeSuccess', function () { + // should be rather done by routing + $(function () { + // make sure all popover handles were registered + openOrClose(); + }); + }); + + } + }; + } +})(); \ No newline at end of file diff --git a/plugins/CoreHome/angularjs/reporting-menu/reportingmenu-model.js b/plugins/CoreHome/angularjs/reporting-menu/reportingmenu-model.js new file mode 100644 index 0000000000..adc1b97936 --- /dev/null +++ b/plugins/CoreHome/angularjs/reporting-menu/reportingmenu-model.js @@ -0,0 +1,153 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ +(function () { + angular.module('piwikApp').factory('reportingMenuModel', reportingMenuModelService); + + reportingMenuModelService.$inject = ['$filter', '$q', 'piwikApi', 'reportingPagesModel', '$location']; + + function reportingMenuModelService ($filter, $q, piwikApi, reportingPagesModel, $location) { + + // those sites are going to be displayed + var model = { + menu: [], + selected: [], + fetchMenuItems: fetchMenuItems, + reloadMenuItems: reloadMenuItems, + findSubcategory: findSubcategory + }; + + return model; + + function isNumeric(text) { + return !isNaN(parseFloat(text)) && isFinite(text); + } + + function findSubcategory(categoryId, subcategoryId) + { + var foundCategory = null; + var foundSubcategory = null; + + angular.forEach(model.menu, function (category) { + if (category.id !== categoryId) { + return; + } + angular.forEach(category.subcategories, function (subcategory) { + if (subcategory.id === subcategoryId) { + foundCategory = category; + foundSubcategory = subcategory; + } + }); + }); + + return {category: foundCategory, subcategory: foundSubcategory}; + } + + function buildMenuFromPages(pages) + { + var menu = []; + + var activeCategory = $location.search().category; + var activeSubcategory = $location.search().subcategory; + + var categoriesHandled = {}; + angular.forEach(pages, function (page, key) { + var category = page.category; + var categoryId = category.id; + + if (categoriesHandled[categoryId]) { + return; + } + + categoriesHandled[categoryId] = true; + + if (activeCategory && category.id === activeCategory) { + // this doesn't really belong here but placed it here for convenience + category.active = true; + category.hover = true; + } + + category.subcategories = []; + + var goalsGroup = false; + + angular.forEach(pages, function (page, key) { + if (page.category.id === categoryId) { + var subcategory = page.subcategory; + + if (subcategory.id === activeSubcategory) { + subcategory.active = true; + } + + if (page.widgets && page.widgets[0] && page.category.id === 'Goals_Goals' && isNumeric(page.subcategory.id)) { + // we handle a goal + if (!goalsGroup) { + goalsGroup = angular.copy(subcategory); + goalsGroup.name = $filter('translate')('Goals_ChooseGoal'); + goalsGroup.isGroup = true; + goalsGroup.subcategories = []; + goalsGroup.order = 10; + } + + if (subcategory.active) { + goalsGroup.name = subcategory.name; + } + + var goalId = page.subcategory.id; + subcategory.tooltip = subcategory.name + ' (id = ' + goalId + ' )'; + + goalsGroup.subcategories.push(subcategory); + return; + } + + category.subcategories.push(subcategory); + } + }); + + if (goalsGroup && goalsGroup.subcategories && goalsGroup.subcategories.length <= 3) { + angular.forEach(goalsGroup.subcategories, function (subcategory) { + category.subcategories.push(subcategory); + }); + } else if(goalsGroup) { + category.subcategories.push(goalsGroup); + } + + category.subcategories = sortMenuItems(category.subcategories); + + menu.push(category); + + return menu; + }); + + menu = sortMenuItems(menu); + + return menu; + } + + function sortMenuItems(menu) { + return $filter('orderBy')(menu, 'order'); + }; + + function reloadMenuItems() + { + var pagesPromise = reportingPagesModel.reloadAllPages(); + return pagesPromise.then(function (pages) { + model.menu = buildMenuFromPages(pages); + }); + } + + function fetchMenuItems() + { + var pagesPromise = reportingPagesModel.getAllPages(); + + return pagesPromise.then(function (pages) { + model.menu = buildMenuFromPages(pages); + + return model.menu; + }); + } + } +})(); \ No newline at end of file diff --git a/plugins/CoreHome/angularjs/reporting-menu/reportingmenu.controller.js b/plugins/CoreHome/angularjs/reporting-menu/reportingmenu.controller.js new file mode 100644 index 0000000000..85dc0f17c5 --- /dev/null +++ b/plugins/CoreHome/angularjs/reporting-menu/reportingmenu.controller.js @@ -0,0 +1,125 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ +(function () { + angular.module('piwikApp').controller('ReportingMenuController', ReportingMenuController); + + ReportingMenuController.$inject = ['$scope', 'piwik', '$location', '$timeout', 'reportingMenuModel', '$rootScope']; + + function ReportingMenuController($scope, piwik, $location, $timeout, menuModel, $rootScope) { + + function markAllCategoriesAsInactive() + { + angular.forEach(menuModel.menu, function (cat) { + cat.active = false; + cat.hover = false; + angular.forEach(cat.subcategories, function (subcat) { + subcat.active = false; + }); + }); + } + + function getUrlParam(param) + { + var value = piwik.broadcast.getValueFromHash(param); + if (!value) { + value = piwik.broadcast.getValueFromUrl(param); + } + return value; + } + + $scope.menuModel = menuModel; + + var timeoutPromise = null; + + // show subcategories of the currently hovered category + $scope.enterCategory = function (category) { + + if (timeoutPromise) { + $timeout.cancel(timeoutPromise); + } + + angular.forEach(menuModel.menu, function (cat) { + cat.hover = false; + }); + + category.hover = true; + }; + + // show subcategories of the current active category again (after 2 sec max) + $scope.leaveCategory = function (category) { + + if (timeoutPromise) { + $timeout.cancel(timeoutPromise); + } + + timeoutPromise = $timeout(function () { + angular.forEach(menuModel.menu, function (cat) { + if (cat.active) { + cat.hover = true; + } else { + cat.hover = false; + } + }); + }, 2000); + }; + + // highlight the currently hovered subcategory (and category) + $scope.enterSubcategory = function (category, subcategory) { + if (!category || !subcategory) { + return; + } + + markAllCategoriesAsInactive(); + + category.active = true; + category.hover = true; + subcategory.active = true; + }; + + var idSite = getUrlParam('idSite'); + var period = getUrlParam('period'); + var date = getUrlParam('date'); + var segment = getUrlParam('segment'); + + $scope.makeUrl = function (category, subcategory) { + var url = 'idSite=' + idSite + '&period=' + period + '&date=' + date + '&category=' + category.id + '&subcategory=' + subcategory.id; + if (segment) { + url+= '&segment='+ segment; + } + return url; + } + + $scope.loadSubcategory = function (category, subcategory) { + if (subcategory && subcategory.active) { + // this menu item is already active, a location change success would not be triggered, + // instead trigger an event + $rootScope.$emit('loadPage', category.id, subcategory.id); + } + }; + + menuModel.fetchMenuItems().then(function (menu) { + if (!$location.search().subcategory) { + // load first, initial page if no subcategory is present + $scope.enterSubcategory(menu[0], menu[0].subcategories[0]); + $location.search($scope.makeUrl(menu[0], menu[0].subcategories[0])); + } + }); + + $rootScope.$on('$locationChangeSuccess', function () { + var category = $location.search().category; + var subcategory = $location.search().subcategory; + + if (!category || !subcategory) { + return; + } + + var found = menuModel.findSubcategory(category, subcategory); + $scope.enterSubcategory(found.category, found.subcategory); + }); + + } +})(); diff --git a/plugins/CoreHome/angularjs/reporting-menu/reportingmenu.directive.html b/plugins/CoreHome/angularjs/reporting-menu/reportingmenu.directive.html new file mode 100644 index 0000000000..bbfd687517 --- /dev/null +++ b/plugins/CoreHome/angularjs/reporting-menu/reportingmenu.directive.html @@ -0,0 +1,40 @@ + \ No newline at end of file diff --git a/plugins/CoreHome/angularjs/reporting-menu/reportingmenu.directive.js b/plugins/CoreHome/angularjs/reporting-menu/reportingmenu.directive.js new file mode 100644 index 0000000000..7cdd9e951b --- /dev/null +++ b/plugins/CoreHome/angularjs/reporting-menu/reportingmenu.directive.js @@ -0,0 +1,31 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +/** + * Shows the Piwik reporting menu. + * + * It automatically calls the API to fetch all data. + * + * Example: + *
+ */ + +(function () { + angular.module('piwikApp').directive('piwikReportingMenu', piwikReportingMenu); + + piwikReportingMenu.$inject = ['piwik']; + + function piwikReportingMenu(piwik){ + + return { + restrict: 'A', + scope: {}, + templateUrl: 'plugins/CoreHome/angularjs/reporting-menu/reportingmenu.directive.html?cb=' + piwik.cacheBuster, + controller: 'ReportingMenuController' + }; + } +})(); \ No newline at end of file diff --git a/plugins/CoreHome/angularjs/reporting-page/reportingpage-model.js b/plugins/CoreHome/angularjs/reporting-page/reportingpage-model.js new file mode 100644 index 0000000000..4018fcee8c --- /dev/null +++ b/plugins/CoreHome/angularjs/reporting-page/reportingpage-model.js @@ -0,0 +1,196 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ +(function () { + angular.module('piwikApp').factory('reportingPageModel', reportingPageModelService); + + reportingPageModelService.$inject = ['$filter', 'piwikApi', 'reportingPagesModel', 'reportMetadataModel']; + + function reportingPageModelService ($filter, piwikApi, reportingPagesModel, reportMetadataModel) { + var init = false; + + // those sites are going to be displayed + var model = { + fetchPage: fetchPage, + resetPage: resetPage, + widgets: [], + page: null, + pageContentUrl: '', + evolutionReports: [], + sparklineReports: [] + }; + + return model; + + function resetPage() + { + model.page = null; + model.widgets = []; + model.pageContentUrl = ''; + model.evolutionReports = []; + model.sparklineReports = []; + } + + function sortWidgets(widgets) + { + return $filter('orderBy')(widgets, 'order'); + } + + function shouldBeRenderedWithFullWidth(widget) + { + // rather controller logic + if ((widget.isContainer && widget.layout && widget.layout === 'ByDimension') + || widget.viewDataTable === 'bydimension') { + return true; + } + + return widget.viewDataTable && widget.viewDataTable === 'tableAllColumns'; + } + + function buildPage(page) + { + if (!page) { + return; + } + + var widgets = []; + var evolutionReports = []; + var sparklineReports = []; + var reportsToIgnore = []; + + angular.forEach(page.widgets, function (widget) { + + if (isIgnoredReport(reportsToIgnore, widget)) { + return; + } + + reportsToIgnore = reportsToIgnore.concat(getRelatedReports(widget)); + + if (widget.viewDataTable && widget.viewDataTable === 'graphEvolution') { + evolutionReports.push(widget); + } else if (widget.viewDataTable && widget.viewDataTable === 'sparklines') { + sparklineReports.push(widget); + } else { + widgets.push(widget); + } + }); + + widgets = sortWidgets(widgets); + + var groupedWidgets = []; + + if (widgets.length === 1) { + // if there is only one widget, we always display it full width + groupedWidgets = widgets; + } else { + for (var i = 0; i < widgets.length; i++) { + var widget = widgets[i]; + + if (shouldBeRenderedWithFullWidth(widget) || (widgets[i+1] && shouldBeRenderedWithFullWidth(widgets[i+1]))) { + widget.widgets = sortWidgets(widget.widgets); + + groupedWidgets.push(widget); + } else { + + var counter = 0; + var left = [widget]; + var right = []; + + while (widgets[i+1] && !shouldBeRenderedWithFullWidth(widgets[i+1])) { + i++; + counter++; + if (counter % 2 === 0) { + left.push(widgets[i]); + } else { + right.push(widgets[i]); + } + } + + groupedWidgets.push({group: true, left: left, right: right}); + } + } + } + + var copyWidgets = angular.copy(groupedWidgets); + var copyEvolution = angular.copy(evolutionReports); + var copySparklines = angular.copy(sparklineReports); + + if (copyEvolution.length) { + copyEvolution = markWidgetsInFirstRowOfPage(copyEvolution); + } else if (copySparklines.length) { + copySparklines = markWidgetsInFirstRowOfPage(copySparklines); + } else { + copyWidgets = markWidgetsInFirstRowOfPage(copyWidgets); + } + + // angular.copy forces the page to re-render. Otherwise it won't reload some pages + model.evolutionReports = copyEvolution; + model.sparklineReports = copySparklines; + model.widgets = copyWidgets; + } + + function markWidgetsInFirstRowOfPage(widgets) + { + if (widgets && widgets[0]) { + if (widgets[0].group) { + markWidgetsInFirstRowOfPage(widgets[0].left); + markWidgetsInFirstRowOfPage(widgets[0].right); + } else { + widgets[0].isFirstInPage = true; + } + } + + return widgets; + } + + function getRelatedReports(widget) + { + if (widget.isReport) { + var report = reportMetadataModel.findReport(widget.module, widget.action); + + if (report && report.relatedReports) { + return report.relatedReports; + } + } + + return []; + } + + function isIgnoredReport(reportsToIgnore, widget) + { + var found = false; + + if (widget.isReport) { + angular.forEach(reportsToIgnore, function (report) { + if (report.module === widget.module && + report.action === widget.action) { + found = true; + } + }); + } + + return found; + } + + function fetchPage(category, subcategory) + { + resetPage(); + + var pagesPromise = reportingPagesModel.getAllPages(); + var reportsPromise = reportMetadataModel.fetchReportMetadata(); + + return pagesPromise.then(function () { + model.page = reportingPagesModel.findPage(category, subcategory); + + reportsPromise.then(function () { + buildPage(model.page); + }); + + return model.page; + }); + } + } +})(); \ No newline at end of file diff --git a/plugins/CoreHome/angularjs/reporting-page/reportingpage.controller.js b/plugins/CoreHome/angularjs/reporting-page/reportingpage.controller.js new file mode 100644 index 0000000000..cf0d424b55 --- /dev/null +++ b/plugins/CoreHome/angularjs/reporting-page/reportingpage.controller.js @@ -0,0 +1,56 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ +(function () { + angular.module('piwikApp').controller('ReportingPageController', ReportingPageController); + + ReportingPageController.$inject = ['$scope', 'piwik', '$rootScope', '$location', 'reportingPageModel']; + + function ReportingPageController($scope, piwik, $rootScope, $location, pageModel) { + pageModel.resetPage(); + $scope.pageModel = pageModel; + + var currentCategory = null; + var currentSubcategory = null; + + $scope.renderPage = function (category, subcategory) { + if (!category || !subcategory) { + pageModel.resetPage(); + $scope.loading = false; + return; + } + + currentCategory = category; + currentSubcategory = subcategory; + + pageModel.fetchPage(category, subcategory).then(function () { + $scope.hasNoPage = !pageModel.page; + $scope.loading = false; + }); + } + + $scope.loading = true; // we only set loading on initial load + + $scope.renderPage($location.search().category, $location.search().subcategory); + + $rootScope.$on('$locationChangeSuccess', function () { + // should be handled by $route + var category = $location.search().category; + var subcategory = $location.search().subcategory; + + if (category === currentCategory && subcategory === currentSubcategory) { + // this page is already loaded + return; + } + + $scope.renderPage(category, subcategory); + }); + + $rootScope.$on('loadPage', function (event, category, subcategory) { + $scope.renderPage(category, subcategory); + }); + } +})(); diff --git a/plugins/CoreHome/angularjs/reporting-page/reportingpage.directive.html b/plugins/CoreHome/angularjs/reporting-page/reportingpage.directive.html new file mode 100644 index 0000000000..9a8974e313 --- /dev/null +++ b/plugins/CoreHome/angularjs/reporting-page/reportingpage.directive.html @@ -0,0 +1,25 @@ +
+ +
+ +
{{ 'CoreHome_NoSuchPage'|translate }}
+ +
+
+
+ +
+
+
+ +
+
+ +
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/plugins/CoreHome/angularjs/reporting-page/reportingpage.directive.js b/plugins/CoreHome/angularjs/reporting-page/reportingpage.directive.js new file mode 100644 index 0000000000..a146ed3112 --- /dev/null +++ b/plugins/CoreHome/angularjs/reporting-page/reportingpage.directive.js @@ -0,0 +1,31 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +/** + * Shows a piwik reporting page. + * + * The content to be displayed is automatically loaded via API based on the current URL. The URL parameters + * 'category' and 'subcategory' need to be present in the URL in order to see something in the reporting page. + * + * Example: + *
+ */ +(function () { + angular.module('piwikApp').directive('piwikReportingPage', piwikReportingPage); + + piwikReportingPage.$inject = ['piwik']; + + function piwikReportingPage(piwik){ + + return { + restrict: 'A', + scope: {}, + templateUrl: 'plugins/CoreHome/angularjs/reporting-page/reportingpage.directive.html?cb=' + piwik.cacheBuster, + controller: 'ReportingPageController' + }; + } +})(); \ No newline at end of file diff --git a/plugins/CoreHome/angularjs/widget-bydimension-container/widget-bydimension-container.directive.html b/plugins/CoreHome/angularjs/widget-bydimension-container/widget-bydimension-container.directive.html new file mode 100644 index 0000000000..db98dee895 --- /dev/null +++ b/plugins/CoreHome/angularjs/widget-bydimension-container/widget-bydimension-container.directive.html @@ -0,0 +1,25 @@ +
+ +
+
+ {{ category.name }} +
    +
  • + {{widget.name}} +
  • +
+
+
+ +
+

{{ selectedWidget.name }}

+ +
+
+
+ +
\ No newline at end of file diff --git a/plugins/CoreHome/angularjs/widget-bydimension-container/widget-bydimension-container.directive.js b/plugins/CoreHome/angularjs/widget-bydimension-container/widget-bydimension-container.directive.js new file mode 100644 index 0000000000..1620be2a9d --- /dev/null +++ b/plugins/CoreHome/angularjs/widget-bydimension-container/widget-bydimension-container.directive.js @@ -0,0 +1,67 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +/** + * Renders a widget that is a container widget having the layout "ByDimension". + * + * The "ByDimension" layout shows a menu on the left letting you choose any widgets within this container. The + * currently selected widget is shown on the right. + * + * @param {Object} piwikWidgetByDimensionContainer a widget object as returned by the WidgetMetadata API. + * + * Example: + *
+ */ +(function () { + angular.module('piwikApp').directive('piwikWidgetByDimensionContainer', piwikWidgetContainer); + + piwikWidgetContainer.$inject = ['piwik', '$filter']; + + function piwikWidgetContainer(piwik, $filter){ + return { + restrict: 'A', + scope: { + container: '=piwikWidgetByDimensionContainer' + }, + templateUrl: 'plugins/CoreHome/angularjs/widget-bydimension-container/widget-bydimension-container.directive.html?cb=' + piwik.cacheBuster, + compile: function (element, attrs) { + + return function (scope, element, attrs, ngModel) { + + var widgetsSorted = $filter('orderBy')(scope.container.widgets, 'order'); + var widgetsByCategory = {}; + + angular.forEach(widgetsSorted, function (widget) { + var category = widget.subcategory.name; + + if (!widgetsByCategory[category]) { + widgetsByCategory[category] = {name: category, order: widget.order, widgets: []}; + } + + widgetsByCategory[category].widgets.push(widget); + }); + + // only an array can be sorted + var finalWidgetsByCategory = []; + angular.forEach(widgetsByCategory, function (category) { + finalWidgetsByCategory.push(category); + }); + + scope.widgetsByCategory = $filter('orderBy')(finalWidgetsByCategory, 'order'); + + scope.selectWidget = function (widget) { + scope.selectedWidget = widget; + } + + if (widgetsSorted && widgetsSorted.length) { + scope.selectWidget(widgetsSorted[0]); + } + }; + } + }; + } +})(); \ No newline at end of file diff --git a/plugins/CoreHome/angularjs/widget-container/widgetcontainer.directive.html b/plugins/CoreHome/angularjs/widget-container/widgetcontainer.directive.html new file mode 100644 index 0000000000..21ebd3d0cd --- /dev/null +++ b/plugins/CoreHome/angularjs/widget-container/widgetcontainer.directive.html @@ -0,0 +1,10 @@ +
+ + + +
+
+
+
\ No newline at end of file diff --git a/plugins/CoreHome/angularjs/widget-container/widgetcontainer.directive.js b/plugins/CoreHome/angularjs/widget-container/widgetcontainer.directive.js new file mode 100644 index 0000000000..c378637c71 --- /dev/null +++ b/plugins/CoreHome/angularjs/widget-container/widgetcontainer.directive.js @@ -0,0 +1,32 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +/** + * Renders a widget that is a container widget having no specific layout (which is the default). + * + * It shows all widgets vertically aligned one widget after another. + * + * @param {Object} piwikWidgetContainer a widget object as returned by the WidgetMetadata API. + * + * Example: + *
+ */ +(function () { + angular.module('piwikApp').directive('piwikWidgetContainer', piwikWidgetContainer); + + piwikWidgetContainer.$inject = ['piwik']; + + function piwikWidgetContainer(piwik){ + return { + restrict: 'A', + scope: { + container: '=piwikWidgetContainer' + }, + templateUrl: 'plugins/CoreHome/angularjs/widget-container/widgetcontainer.directive.html?cb=' + piwik.cacheBuster + }; + } +})(); \ No newline at end of file diff --git a/plugins/CoreHome/angularjs/widget-loader/widgetloader.directive.html b/plugins/CoreHome/angularjs/widget-loader/widgetloader.directive.html new file mode 100644 index 0000000000..d1f0cb51f1 --- /dev/null +++ b/plugins/CoreHome/angularjs/widget-loader/widgetloader.directive.html @@ -0,0 +1,13 @@ +
+ +
+ +
+
+ {{ 'General_ErrorRequest'|translate:(''):('') }} +
+
+ +
+ +
\ No newline at end of file diff --git a/plugins/CoreHome/angularjs/widget-loader/widgetloader.directive.js b/plugins/CoreHome/angularjs/widget-loader/widgetloader.directive.js new file mode 100644 index 0000000000..4e1859e789 --- /dev/null +++ b/plugins/CoreHome/angularjs/widget-loader/widgetloader.directive.js @@ -0,0 +1,134 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +/** + * Loads any custom widget or URL based on the given parameters. + * + * The currently active idSite, period, date and segment (if needed) is automatically appended to the parameters. If + * this widget is removed from the DOM and requests are in progress, these requests will be aborted. A loading message + * or an error message on failure is shown as well. It's kinda similar to ng-include but there it is not possible to + * listen to HTTP errors etc. + * + * Example: + *
+ */ +(function () { + angular.module('piwikApp').directive('piwikWidgetLoader', piwikWidgetLoader); + + piwikWidgetLoader.$inject = ['piwik', 'piwikUrl', '$http', '$compile', '$q']; + + function piwikWidgetLoader(piwik, piwikUrl, $http, $compile, $q){ + return { + restrict: 'A', + transclude: true, + scope: { + piwikWidgetLoader: '=' + }, + templateUrl: 'plugins/CoreHome/angularjs/widget-loader/widgetloader.directive.html?cb=' + piwik.cacheBuster, + compile: function (element, attrs) { + + return function (scope, element, attrs, ngModel) { + var changeCounter = 0, + currentScope, + currentElement, + httpCanceler, + contentNode = element.find('.theWidgetContent'); + + var cleanupLastWidgetContent = function() { + if (currentElement) { + currentElement.remove(); + currentElement = null; + } + if (currentScope) { + currentScope.$destroy(); + currentScope = null; + } + }; + + var abortHttpRequestIfNeeded = function () { + if (httpCanceler) { + httpCanceler.resolve(); + httpCanceler = null; + } + } + + function getFullWidgetUrl(parameters) { + + var url = $.param(parameters); + + var idSite = piwikUrl.getSearchParam('idSite'); + var period = piwikUrl.getSearchParam('period'); + var date = piwikUrl.getSearchParam('date'); + var segment = piwikUrl.getSearchParam('segment'); + + url += '&idSite=' + idSite + '&period=' + period; + url += '&date=' + date + '&random=' + parseInt(Math.random() * 10000); + + if (segment) { + url += '&segment=' + segment; + } + + return '?' + url; + } + + function loadWidgetUrl(parameters, thisChangeId) + { + scope.loading = true; + + var url = getFullWidgetUrl(parameters); + + abortHttpRequestIfNeeded(); + cleanupLastWidgetContent(); + + httpCanceler = $q.defer(); + + $http.get(url, {timeout: httpCanceler.promise}).success(function(response) { + if (thisChangeId !== changeCounter || !response) { + // another widget was requested meanwhile, ignore this response + return; + } + + httpCanceler = null; + + var newScope = scope.$new(); + currentScope = newScope; + + scope.loading = false; + scope.loadingFailed = false; + + currentElement = contentNode.html(response).children(); + $compile(currentElement)(newScope); + + }).error(function () { + if (thisChangeId !== changeCounter) { + // another widget was requested meanwhile, ignore this response + return; + } + + httpCanceler = null; + + cleanupLastWidgetContent(); + + scope.loading = false; + scope.loadingFailed = true; + }); + } + + scope.$watch('piwikWidgetLoader', function (parameters, oldUrl) { + if (parameters) { + loadWidgetUrl(parameters, ++changeCounter); + } + }); + + element.on('$destroy', function() { + abortHttpRequestIfNeeded(); + }); + }; + } + }; + } +})(); \ No newline at end of file diff --git a/plugins/CoreHome/angularjs/widget/widget.directive.html b/plugins/CoreHome/angularjs/widget/widget.directive.html new file mode 100644 index 0000000000..86cdc91291 --- /dev/null +++ b/plugins/CoreHome/angularjs/widget/widget.directive.html @@ -0,0 +1,23 @@ +
+ +

{{widget.name}}

+

{{widget.name}}

+ +
+ +
+
+
+ +
+
+
+
\ No newline at end of file diff --git a/plugins/CoreHome/angularjs/widget/widget.directive.js b/plugins/CoreHome/angularjs/widget/widget.directive.js new file mode 100644 index 0000000000..86574870f2 --- /dev/null +++ b/plugins/CoreHome/angularjs/widget/widget.directive.js @@ -0,0 +1,93 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +/** + * Renders any kind of widget. If you have a widget and you want to have it rendered, use this directive. It will + * display a name on top and the actual widget below. It can handle any kind of widget, no matter whether it is a + * regular widget or a container. + * + * @param {Object} piwikWidget A widget object as returned by the WidgetMetadata API. + * @param {Object} piwikWidget.middlewareParameters If present, we will request a URL using the given parameters and + * only if this URL returns a JSON `true` the widget will be shown. + * Otherwise the widget won't be shown. + * @param {String} containerId If you do not have a widget object but a containerId we will find the correct widget + * object based on the given containerId. Be aware that we might not find the widget if + * it is for example not available for the current user or period/date. + * @param {Boolean} widgetized true if the widget is widgetized (eg in Dashboard or exported). In this case we will add + * a URL parameter widget=1 to all widgets. Eg sparklines will be then displayed one after + * another (vertically aligned) instead of two next to each other. + * + * Example: + *
+ *
// in this case we will find the correct widget automatically + *
// disables rating feature, no initial headline + */ +(function () { + angular.module('piwikApp').directive('piwikWidget', piwikWidget); + + piwikWidget.$inject = ['piwik', 'piwikApi']; + + function piwikWidget(piwik, piwikApi){ + + function findContainerWidget(containerId, scope) { + widgetsHelper.getAvailableWidgets(function (categorizedWidgets) { + + angular.forEach(categorizedWidgets, function (widgets) { + angular.forEach(widgets, function (widget) { + + if (widget && widget.isContainer && widget.parameters.containerId === containerId) { + widget = angular.copy(widget); + if (scope.widgetized) { + widget.isFirstInPage = '1'; + widget.parameters.widget = '1'; + angular.forEach(widget.widgets, function (widget) { + widget.parameters.widget = '1'; + }); + } + scope.widget = widget; + applyMiddleware(scope); + } + }); + }); + + }); + } + + function applyMiddleware(scope) + { + if (!scope.widget.middlewareParameters) { + scope.$eval('view.showWidget = true'); + } else { + var params = angular.copy(scope.widget.middlewareParameters); + piwikApi.fetch(params).then(function (response) { + var enabled = response ? 'true' : 'false'; + scope.$eval('view.showWidget = ' + enabled); + }); + } + } + + return { + restrict: 'A', + scope: { + widget: '=?piwikWidget', + widgetized: '=?', + containerid: '=' + }, + templateUrl: 'plugins/CoreHome/angularjs/widget/widget.directive.html?cb=' + piwik.cacheBuster, + compile: function (element, attrs) { + + return function (scope, element, attrs, ngModel) { + if (scope.widget) { + applyMiddleware(scope); + } else if (attrs.containerid) { + findContainerWidget(attrs.containerid, scope); + } + } + } + }; + } +})(); \ No newline at end of file diff --git a/plugins/CoreHome/javascripts/broadcast.js b/plugins/CoreHome/javascripts/broadcast.js index 706a8e59d5..3d5fb0432c 100644 --- a/plugins/CoreHome/javascripts/broadcast.js +++ b/plugins/CoreHome/javascripts/broadcast.js @@ -159,7 +159,6 @@ var broadcast = { } else { // start page Piwik_Popover.close(); - $('.pageWrap #content:not(.admin)').empty(); } }, @@ -173,6 +172,7 @@ var broadcast = { }, /** + * ONLY USED BY OVERLAY * propagateAjax -- update hash values then make ajax calls. * example : * 1) View keywords report @@ -228,6 +228,47 @@ var broadcast = { } }, + /** + * propagateAjax -- update hash values then make ajax calls. + * example : + * 1) View keywords report + * 2) Main menu li also goes through this function. + * + * Will propagate your new value into the current hash string and make ajax calls. + * + * NOTE: this method will only make ajax call and replacing main content. + * + * @param {string} ajaxUrl querystring with parameters to be updated + * @param {boolean} [disableHistory] the hash change won't be available in the browser history + * @return {void} + */ + buildReportingUrl: function (ajaxUrl, disableHistory) { + + // available in global scope + var currentHashStr = broadcast.getHash(); + + ajaxUrl = ajaxUrl.replace(/^\?|&#/, ''); + + var params_vals = ajaxUrl.split("&"); + for (var i = 0; i < params_vals.length; i++) { + currentHashStr = broadcast.updateParamValue(params_vals[i], currentHashStr); + } + + // if the module is not 'Goals', we specifically unset the 'idGoal' parameter + // this is to ensure that the URLs are clean (and that clicks on graphs work as expected - they are broken with the extra parameter) + var action = broadcast.getParamValue('action', currentHashStr); + if (action != 'goalReport' && action != 'ecommerceReport' && action != 'products' && action != 'sales') { + currentHashStr = broadcast.updateParamValue('idGoal=', currentHashStr); + } + // unset idDashboard if use doesn't display a dashboard + var module = broadcast.getParamValue('module', currentHashStr); + if (module != 'Dashboard') { + currentHashStr = broadcast.updateParamValue('idDashboard=', currentHashStr); + } + + return '#' + currentHashStr; + }, + /** * propagateNewPage() -- update url value and load new page, * Example: @@ -349,9 +390,9 @@ var broadcast = { */ propagateNewPopoverParameter: function (handlerName, value) { // init broadcast if not already done (it is required to make popovers work in widgetize mode) - broadcast.init(true); + //broadcast.init(true); - var hash = broadcast.getHashFromUrl(window.location.href); + var $location = angular.element(document).injector().get('$location'); var popover = ''; if (handlerName) { @@ -365,24 +406,14 @@ var broadcast = { } if ('' == value || 'undefined' == typeof value) { - var newHash = hash.replace(/(&?popover=.*)/, ''); - } else if (broadcast.getParamValue('popover', hash)) { - var newHash = broadcast.updateParamValue('popover='+popover, hash); - } else if (hash && hash != '#') { - var newHash = hash + '&popover=' + popover + $location.search('popover', ''); } else { - var newHash = '#popover='+popover; - } - - // never use an empty hash, as that might reload the page - if ('' == newHash) { - newHash = '#'; + $location.search('popover', popover); } - broadcast.forceReload = false; - angular.element(document).injector().invoke(function (historyService) { - historyService.load(newHash); - }); + setTimeout(function () { + angular.element(document).injector().get('$rootScope').$apply(); + }, 1); }, /** diff --git a/plugins/CoreHome/javascripts/corehome.js b/plugins/CoreHome/javascripts/corehome.js index 5bddc23f9e..6e8729611b 100755 --- a/plugins/CoreHome/javascripts/corehome.js +++ b/plugins/CoreHome/javascripts/corehome.js @@ -114,60 +114,6 @@ handleSectionToggle(this, 'inline', !$(this).is(':checked')); }); - // - // reports by dimension list behavior - // - - // when a report dimension is clicked, load the appropriate report - var currentWidgetLoading = null; - $('body').on('click', '.reportDimension', function (e) { - var view = $(this).closest('.reportsByDimensionView'), - report = $('.dimensionReport', view), - loading = $('.loadingPiwik', view); - - // make this dimension the active one - $('.activeDimension', view).removeClass('activeDimension'); - $(this).addClass('activeDimension'); - - // hide the visible report & show the loading elem - report.hide(); - loading.show(); - - // load the report using the data-url attribute (which holds the URL to the report) - var widgetParams = broadcast.getValuesFromUrl($(this).attr('data-url')); - for (var key in widgetParams) { - widgetParams[key] = decodeURIComponent(widgetParams[key]); - } - - var widgetUniqueId = widgetParams.module + widgetParams.action; - currentWidgetLoading = widgetUniqueId; - - widgetsHelper.loadWidgetAjax(widgetUniqueId, widgetParams, function (response) { - // if the widget that was loaded was not for the latest clicked link, do nothing w/ the response - if (widgetUniqueId != currentWidgetLoading) { - return; - } - - loading.hide(); - report.css('display', 'inline-block').html($(response)); - - // scroll to report - piwikHelper.lazyScrollTo(report, 400); - }, function (deferred, status) { - if (status == 'abort' || !deferred || deferred.status < 400 || deferred.status >= 600) { - return; - } - - loading.hide(); - - var errorMessage = _pk_translate('General_ErrorRequest', ['', '']); - if ($('#loadingError').html()) { - errorMessage = $('#loadingError').html(); - } - - report.css('display', 'inline-block').html('
' + errorMessage + '
'); - }); - }); }); }(jQuery)); diff --git a/plugins/CoreHome/javascripts/dataTable.js b/plugins/CoreHome/javascripts/dataTable.js index 0561185de8..4bd5fb609a 100644 --- a/plugins/CoreHome/javascripts/dataTable.js +++ b/plugins/CoreHome/javascripts/dataTable.js @@ -1,3 +1,4 @@ + /*! * Piwik - free/libre analytics platform * diff --git a/plugins/CoreHome/javascripts/menu.js b/plugins/CoreHome/javascripts/menu.js deleted file mode 100644 index 2f5e16c827..0000000000 --- a/plugins/CoreHome/javascripts/menu.js +++ /dev/null @@ -1,114 +0,0 @@ -/*! - * Piwik - free/libre analytics platform - * - * @link http://piwik.org - * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later - */ - -/** - * @constructor - */ -function menu() { - this.param = {}; -} - -menu.prototype = -{ - resetTimer: null, - - adaptSubMenuHeight: function() { - var subNavHeight = $('.sfHover > ul').outerHeight(); - $('.nav_sep').height(subNavHeight); - }, - - overMainLI: function () { - var $this = $(this); - $this.siblings().removeClass('sfHover'); - $this.addClass('sfHover'); - menu.prototype.adaptSubMenuHeight(); - clearTimeout(menu.prototype.resetTimer); - }, - - outMainLI: function () { - clearTimeout(menu.prototype.resetTimer); - menu.prototype.resetTimer = setTimeout(function() { - $('.Menu-tabList > .sfHover', this.menuNode).removeClass('sfHover'); - $('.Menu-tabList > .sfActive', this.menuNode).addClass('sfHover'); - menu.prototype.adaptSubMenuHeight(); - }, 2000); - }, - - onItemClick: function (e) { - if (e.which === 2) { - return; - } - $('.Menu--dashboard').trigger('piwikSwitchPage', this); - broadcast.propagateAjax( $(this).attr('href').substr(1) ); - return false; - }, - - init: function () { - this.menuNode = $('.Menu--dashboard'); - - this.menuNode.find("li:has(ul),li#Searchmenu").hover(this.overMainLI, this.outMainLI); - this.menuNode.find("li:has(ul),li#Searchmenu").focusin(this.overMainLI); - - this.menuNode.find('a.menuItem').click(this.onItemClick); - - menu.prototype.adaptSubMenuHeight(); - }, - - activateMenu: function (module, action, params) { - params = params || {}; - params.module = module; - params.action = action; - - this.menuNode.find('li').removeClass('sfHover').removeClass('sfActive'); - var $activeLink = this.menuNode.find('a').filter(function () { - var url = $(this).attr('href'); - if (!url) { - return false; - } - - for (var key in params) { - if (!params.hasOwnProperty(key) - || !params[key] - ) { - continue; - } - - var actual = broadcast.getValueFromHash(key, url); - if (actual != params[key]) { - return false; - } - } - - return true; - }); - - $activeLink.closest('li').addClass('sfHover'); - $activeLink.closest('li.menuTab').addClass('sfActive').addClass('sfHover'); - }, - - // getting the right li is a little tricky since goals uses idGoal, and overview is index. - getSubmenuID: function (module, id, action) { - var $li = ''; - // So, if module is Goals, id is present, and action is not Index, must be one of the goals - if ((module == 'Goals' || module == 'Ecommerce') && id != '' && (action != 'index')) { - $li = $("#" + module + "_" + action + "_" + id); - // if module is Dashboard and id is present, must be one of the dashboards - } else if (module == 'Dashboard') { - if (!id) id = 1; - $li = $("#" + module + "_" + action + "_" + id); - } else { - $li = $("#" + module + "_" + action); - } - return $li; - }, - - loadFirstSection: function () { - if (broadcast.isHashExists() == false) { - $('li:first a:first', this.menuNode).click().addClass('sfHover').addClass('sfActive'); - } - } -}; diff --git a/plugins/CoreHome/javascripts/menu_init.js b/plugins/CoreHome/javascripts/menu_init.js deleted file mode 100644 index 490c859185..0000000000 --- a/plugins/CoreHome/javascripts/menu_init.js +++ /dev/null @@ -1,19 +0,0 @@ -$(function () { - var isPageHasMenu = $('.Menu--dashboard').size(); - var isPageIsAdmin = $('#content.admin').size(); - if (isPageHasMenu) { - piwikMenu = new menu(); - piwikMenu.init(); - piwikMenu.loadFirstSection(); - } - - if(isPageIsAdmin) { - // don't use broadcast in admin pages - return; - } - if(isPageHasMenu) { - broadcast.init(); - } else { - broadcast.init(true); - } -}); diff --git a/plugins/CoreHome/javascripts/sparkline.js b/plugins/CoreHome/javascripts/sparkline.js index fc3b74f692..256e6f1589 100644 --- a/plugins/CoreHome/javascripts/sparkline.js +++ b/plugins/CoreHome/javascripts/sparkline.js @@ -35,14 +35,30 @@ piwik.initSparklines = function() { }; window.initializeSparklines = function () { - var sparklineUrlParamsToIgnore = ['module', 'action', 'idSite', 'period', 'date', 'viewDataTable']; + var sparklineUrlParamsToIgnore = ['module', 'action', 'idSite', 'period', 'date', 'viewDataTable', 'forceView', 'random']; - $("[data-graph-id]").each(function () { + $('.graphEvolution [data-report]').each(function () { var graph = $(this); - // try to find sparklines and add them clickable behaviour - graph.parent().find('div.sparkline').each(function () { + // we search for .widget to make sure eg in the Dashboard to not update any graph of another report + var selectorsToFindParent = ['.widget', '.reporting-page', 'body']; + var index = 0, selector, parent; + for (index; index < selectorsToFindParent.length; index++) { + selector = selectorsToFindParent[index]; + parent = graph.parents(selector).first(); + if (parent && parent.length) { + break; + } + } + + if (!parent || !parent.length) { + return; + } + var sparklines = parent.find('div.sparkline'); + + // try to find sparklines and add them clickable behaviour + sparklines.each(function () { // find the sparkline and get it's src attribute var sparklineUrl = $('img', this).attr('data-src'); @@ -66,8 +82,8 @@ window.initializeSparklines = function () { // on click, reload the graph with the new url $(this).off('click.sparkline'); $(this).on('click.sparkline', function () { - var reportId = graph.attr('data-graph-id'), - dataTable = $(require('piwik/UI').DataTable.getDataTableByReport(reportId)); + var reportId = graph.attr('data-report'), + dataTable = graph; // when the metrics picker is used, the id of the data table might be updated (which is correct behavior). // for example, in goal reports it might change from GoalsgetEvolutionGraph to GoalsgetEvolutionGraph1. diff --git a/plugins/CoreHome/lang/en.json b/plugins/CoreHome/lang/en.json index a6bab4a544..7b3d4bbcf3 100644 --- a/plugins/CoreHome/lang/en.json +++ b/plugins/CoreHome/lang/en.json @@ -48,6 +48,7 @@ "YouAreUsingTheLatestVersion": "You are using the latest version of Piwik!", "ClickRowToExpandOrContract": "Click this row to expand or contract the subtable.", "UndoPivotBySubtable": "This report has been pivoted %s Undo pivot", - "PivotBySubtable": "This report is not pivoted %s Pivot by %s" + "PivotBySubtable": "This report is not pivoted %s Pivot by %s", + "NoSuchPage": "This page does not exist" } } diff --git a/plugins/CoreHome/stylesheets/coreHome.less b/plugins/CoreHome/stylesheets/coreHome.less index 5474eae3d2..63607d749f 100644 --- a/plugins/CoreHome/stylesheets/coreHome.less +++ b/plugins/CoreHome/stylesheets/coreHome.less @@ -120,6 +120,12 @@ div.ui-datepicker { display: none; } +.reporting-page { + .sparklines { + max-width: 1250px; + } +} + div .sparkline { float: left; clear: both; diff --git a/plugins/CoreHome/stylesheets/zen-mode.less b/plugins/CoreHome/stylesheets/zen-mode.less index 124c3395ff..112c6b2da6 100644 --- a/plugins/CoreHome/stylesheets/zen-mode.less +++ b/plugins/CoreHome/stylesheets/zen-mode.less @@ -77,13 +77,25 @@ #content:not(.admin), .widget { - h2:nth-of-type(n+2) { - margin-top: 40px; + .reporting-page { + .smallTopMargin:not(.graphEvolution) { + margin-top: 20px; + } } h2 { + margin-top: 40px; padding-left: 10px; font-size: 24px; + + &.noTopMargin { + margin-top: 0px; + } + } + + .widget [piwik-widget-container] [piwik-widget]:first-child h2 { + // eg Visits Overview with Graph should not have a margin-top + margin-top: 0px; } } diff --git a/plugins/CoreHome/templates/ReportsByDimension/_reportsByDimension.twig b/plugins/CoreHome/templates/ReportsByDimension/_reportsByDimension.twig deleted file mode 100644 index 57ec8279d5..0000000000 --- a/plugins/CoreHome/templates/ReportsByDimension/_reportsByDimension.twig +++ /dev/null @@ -1,29 +0,0 @@ -
- -
- {% for category, dimensions in dimensionCategories %} - {% set firstCategory = (loop.index0 == 0) %} -
- {{ category|translate }} -
    - {% for idx, dimension in dimensions %} -
  • - {{ dimension.title|translate }} -
  • - {% endfor %} -
-
- {% endfor %} -
- -
- - -
{{ firstReport|raw }}
-
-
- -
diff --git a/plugins/CoreHome/templates/_indexContent.twig b/plugins/CoreHome/templates/_indexContent.twig index 46d2f13579..671c26e782 100644 --- a/plugins/CoreHome/templates/_indexContent.twig +++ b/plugins/CoreHome/templates/_indexContent.twig @@ -12,8 +12,11 @@ {{ ajax.loadingDiv() }} +
+
{% if content %}{{ content }}{% endif %} +
diff --git a/plugins/CoreHome/templates/getDefaultIndexView.twig b/plugins/CoreHome/templates/getDefaultIndexView.twig index 7b46ca3f76..4efd453159 100644 --- a/plugins/CoreHome/templates/getDefaultIndexView.twig +++ b/plugins/CoreHome/templates/getDefaultIndexView.twig @@ -4,9 +4,8 @@ {% include "@CoreHome/_siteSelectHeader.twig" %} -{% if (menu is defined and menu) %} - {% include "@CoreHome/_menu.twig" %} -{% endif %} +
+ {% include "@CoreHome/_indexContent.twig" %} diff --git a/plugins/CoreHome/templates/widgetContainer.twig b/plugins/CoreHome/templates/widgetContainer.twig new file mode 100755 index 0000000000..b3eda12997 --- /dev/null +++ b/plugins/CoreHome/templates/widgetContainer.twig @@ -0,0 +1,18 @@ +
+
+ + +
\ No newline at end of file diff --git a/plugins/CoreVisualizations/JqplotDataGenerator/Evolution.php b/plugins/CoreVisualizations/JqplotDataGenerator/Evolution.php index 5675153c34..5114167364 100644 --- a/plugins/CoreVisualizations/JqplotDataGenerator/Evolution.php +++ b/plugins/CoreVisualizations/JqplotDataGenerator/Evolution.php @@ -12,7 +12,6 @@ use Piwik\Archive\DataTableFactory; use Piwik\Common; use Piwik\DataTable; use Piwik\DataTable\Row; -use Piwik\Menu\MenuMain; use Piwik\Plugins\CoreVisualizations\JqplotDataGenerator; use Piwik\Url; @@ -76,7 +75,6 @@ class Evolution extends JqplotDataGenerator $periodLabel = reset($dataTables)->getMetadata(DataTableFactory::TABLE_METADATA_PERIOD_INDEX)->getLabel(); $axisXOnClick = array(); - $queryStringAsHash = $this->getQueryStringAsHash(); foreach ($dataTable->getDataTables() as $metadataDataTable) { $dateInUrl = $metadataDataTable->getMetadata(DataTableFactory::TABLE_METADATA_PERIOD_INDEX)->getDateStart(); $parameters = array( @@ -85,16 +83,7 @@ class Evolution extends JqplotDataGenerator 'date' => $dateInUrl->toString(), 'segment' => \Piwik\API\Request::getRawSegmentFromRequest() ); - $hash = ''; - if (!empty($queryStringAsHash)) { - $hash = '#' . Url::getQueryStringFromParameters($queryStringAsHash + $parameters); - } - $link = 'index.php?' . - Url::getQueryStringFromParameters(array( - 'module' => 'CoreHome', - 'action' => 'index', - ) + $parameters) - . $hash; + $link = Url::getQueryStringFromParameters($parameters); $axisXOnClick[] = $link; } $visualization->setAxisXOnClick($axisXOnClick); @@ -144,34 +133,6 @@ class Evolution extends JqplotDataGenerator return $label; } - /** - * We link the graph dots to the same report as currently being displayed (only the date would change). - * - * In some cases the widget is loaded within a report that doesn't exist as such. - * For example, the dashboards loads the 'Last visits graph' widget which can't be directly linked to. - * Instead, the graph must link back to the dashboard. - * - * In other cases, like Visitors>Overview or the Goals graphs, we can link the graph clicks to the same report. - * - * To detect whether or not we can link to a report, we simply check if the current URL from which it was loaded - * belongs to the menu or not. If it doesn't belong to the menu, we do not append the hash to the URL, - * which results in loading the dashboard. - * - * @return array Query string array to append to the URL hash or false if the dashboard should be displayed - */ - private function getQueryStringAsHash() - { - $queryString = Url::getArrayFromCurrentQueryString(); - $piwikParameters = array('idSite', 'date', 'period', 'XDEBUG_SESSION_START', 'KEY'); - foreach ($piwikParameters as $parameter) { - unset($queryString[$parameter]); - } - if (MenuMain::getInstance()->isUrlFound($queryString)) { - return $queryString; - } - return false; - } - private function isLinkEnabled() { static $linkEnabled; diff --git a/plugins/CoreVisualizations/Visualizations/Sparkline.php b/plugins/CoreVisualizations/Visualizations/Sparkline.php index 2ca75bbcfe..3c1dbf5a56 100644 --- a/plugins/CoreVisualizations/Visualizations/Sparkline.php +++ b/plugins/CoreVisualizations/Visualizations/Sparkline.php @@ -25,7 +25,7 @@ class Sparkline extends ViewDataTable * @see ViewDataTable::main() * @return mixed */ - protected function buildView() + public function render() { // If period=range, we force the sparkline to draw daily data points $period = Common::getRequestVar('period'); @@ -58,7 +58,7 @@ class Sparkline extends ViewDataTable $graph->main(); - return $graph; + return $graph->render(); } /** diff --git a/plugins/CoreVisualizations/Visualizations/Sparklines.php b/plugins/CoreVisualizations/Visualizations/Sparklines.php new file mode 100644 index 0000000000..3b576c885e --- /dev/null +++ b/plugins/CoreVisualizations/Visualizations/Sparklines.php @@ -0,0 +1,147 @@ +config->addSparklineMetric('nb_visits'); // if an array of metrics given, they will be displayed comma separated + * $view->config->addTranslation('nb_visits', 'Visits'); + * Results in: [sparkline image] X visits + * Data is fetched from the configured $view->requestConfig->apiMethodToRequestDataTable. + * + * In case you want to add any custom sparklines from any other API method you can call + * {@link Sparklines\Config::addSparkline()}. + * + * Example: + * $sparklineUrlParams = array('columns' => array('nb_visits)); + * $evolution = array('currentValue' => 5, 'pastValue' => 10, 'tooltip' => 'Foo bar'); + * $view->config->addSparkline($sparklineUrlParams, $value = 5, $description = 'Visits', $evolution); + * + * @property Sparklines\Config $config + */ +class Sparklines extends ViewDataTable +{ + const ID = 'sparklines'; + + public static function getDefaultConfig() + { + return new Sparklines\Config(); + } + + /** + * @see ViewDataTable::main() + * @return mixed + */ + public function render() + { + $view = new View('@CoreVisualizations/_dataTableViz_sparklines.twig'); + + $columnsList = array(); + if ($this->config->hasSparklineMetrics()) { + foreach ($this->config->getSparklineMetrics() as $cols) { + $columnsList = array_merge($cols['columns'], $columnsList); + } + } + + $this->requestConfig->request_parameters_to_modify['columns'] = $columnsList; + $this->requestConfig->request_parameters_to_modify['format_metrics'] = '1'; + + if (!empty($this->requestConfig->apiMethodToRequestDataTable)) { + $this->fetchConfiguredSparklines(); + } + + $view->sparklines = $this->config->getSortedSparklines(); + + return $view->render(); + } + + private function fetchConfiguredSparklines() + { + $data = $this->loadDataTableFromAPI(); + + $this->applyFilters($data); + + if (!$this->config->hasSparklineMetrics()) { + foreach ($data->getColumns() as $column) { + $this->config->addSparklineMetric($column); + } + } + + $translations = $this->config->translations; + + $firstRow = $data->getFirstRow(); + + foreach ($this->config->getSparklineMetrics() as $sparklineMetric) { + $column = $sparklineMetric['columns']; + $order = $sparklineMetric['order']; + + if ($column === 'label') { + continue; + } + + if (empty($column)) { + $this->config->addPlaceholder($order); + continue; + } + + if (!is_array($column)) { + $column = array($column); + } + + $values = array(); + $descriptions = array(); + + foreach ($column as $col) { + $value = $firstRow->getColumn($col); + + if ($value === false) { + $value = 0; + } + + $values[] = $value; + $descriptions[] = isset($translations[$col]) ? $translations[$col] : $col; + } + + $sparklineUrlParams = array( + 'columns' => $column, + 'module' => $this->requestConfig->getApiModuleToRequest(), + 'action' => $this->requestConfig->getApiMethodToRequest() + ); + + $this->config->addSparkline($sparklineUrlParams, $values, $descriptions, null, $order); + } + } + + private function applyFilters(DataTable\DataTableInterface $table) + { + foreach ($this->config->getPriorityFilters() as $filter) { + $table->filter($filter[0], $filter[1]); + } + + // queue other filters so they can be applied later if queued filters are disabled + foreach ($this->config->getPresentationFilters() as $filter) { + $table->queueFilter($filter[0], $filter[1]); + } + + $table->applyQueuedFilters(); + } +} diff --git a/plugins/CoreVisualizations/Visualizations/Sparklines/Config.php b/plugins/CoreVisualizations/Visualizations/Sparklines/Config.php new file mode 100644 index 0000000000..ca54a6d564 --- /dev/null +++ b/plugins/CoreVisualizations/Visualizations/Sparklines/Config.php @@ -0,0 +1,354 @@ +translations = Metrics::getDefaultMetricTranslations(); + } + + /** + * @ignore + * @return array + */ + public function getSparklineMetrics() + { + return $this->sparkline_metrics; + } + + /** + * @ignore + * @return bool + */ + public function hasSparklineMetrics() + { + return !empty($this->sparkline_metrics); + } + + /** + * Removes an existing sparkline entry. Especially useful in dataTable filters in case sparklines should be not + * displayed depending on the fetched data. + * + * Example: + * $config->addSparklineMetric('nb_users'); + * $config->filters[] = function ($dataTable) use ($config) { + * if ($dataTable->getFirstRow()->getColumn('nb_users') == 0) { + * // do not show a sparkline if there are no recorded users + * $config->removeSparklineMetric('nb_users'); + * } + * } + * + * @param array|string $metricNames The name of the metrics in the same format they were used when added via + * {@link addSparklineMetric} + */ + public function removeSparklineMetric($metricNames) + { + foreach ($this->sparkline_metrics as $index => $metric) { + if ($metric['columns'] === $metricNames) { + array_splice($this->sparkline_metrics, $index, 1); + + break; + } + } + } + + /** + * Replaces an existing sparkline entry with different columns. Especially useful in dataTable filters in case + * sparklines should be not displayed depending on the fetched data. + * + * Example: + * $config->addSparklineMetric('nb_users'); + * $config->filters[] = function ($dataTable) use ($config) { + * if ($dataTable->getFirstRow()->getColumn('nb_users') == 0) { + * // instead of showing the sparklines for users, show a placeholder if there are no recorded users + * $config->replaceSparklineMetric(array('nb_users'), ''); + * } + * } + * + * @param array|string $metricNames The name of the metrics in the same format they were used when added via + * {@link addSparklineMetric} + * @param array|string $replacementColumns The removed columns will be replaced with these columns + */ + public function replaceSparklineMetric($metricNames, $replacementColumns) + { + foreach ($this->sparkline_metrics as $index => $metric) { + if ($metric['columns'] === $metricNames) { + $this->sparkline_metrics[$index]['columns'] = $replacementColumns; + } + } + } + + /** + * Adds a new sparkline. + * + * It will show a sparkline image, the value of the resolved metric name and a descrption. Optionally, multiple + * values can be shown after a sparkline image by passing multiple metric names + * (eg array('nb_visits', 'nb_actions')). The data will be requested from the configured api method see + * {@link Piwik\ViewDataTable\RequestConfig::$apiMethodToRequestDataTable}. + * + * Example: + * $config->addSparklineMetric('nb_visits'); + * $config->addTranslation('nb_visits', 'Visits'); + * Results in: [sparkline image] X visits + * + * Example: + * $config->addSparklineMetric(array('nb_visits', 'nb_actions')); + * $config->addTranslations(array('nb_visits' => 'Visits', 'nb_actions' => 'Actions')); + * Results in: [sparkline image] X visits, Y actions + * + * @param string|array $metricName Either one metric name (eg 'nb_visits') or an array of metric names + * @param int|null $order Defines the order. The lower the order the earlier the sparkline will be displayed. + * By default the sparkline will be appended to the end. + */ + public function addSparklineMetric($metricName, $order = null) + { + $this->sparkline_metrics[] = array( + 'columns' => $metricName, + 'order' => $order + ); + } + + /** + * Adds a placeholder. In this case nothing will be shown, neither a sparkline nor any description. This can be + * useful if you want to have some kind of separator. Eg if you want to have a sparkline on the left side but + * not sparkline on the right side. + * + * @param int|null $order Defines the order. The lower the order the earlier the sparkline will be displayed. + * By default the sparkline will be appended to the end. + */ + public function addPlaceholder($order = null) + { + $this->sparklines[] = array( + 'url' => '', + 'metrics' => array(), + 'order' => $this->getSparklineOrder($order) + ); + } + + /** + * Add a new sparkline to be displayed to the view. + * + * Each sparkline can consist of one or multiple metrics. One metric consists of a value and a description. By + * default the value is shown first, then the description. The description can optionally contain a '%s' in case + * the value shall be displayed within the description. If multiple metrics are given, they will be separated by + * a comma. + * + * @param array $requestParamsForSparkline You need to at least set a module / action eg + * array('columns' => array('nb_visit'), 'module' => '', 'action' => '') + * @param int|float|string|array $value Either the metric value or an array of values. + * @param string|array $description Either one description or an array of descriptions. If an array, both + * $value and $description need the same amount of array entries. + * $description[0] should be the description for $value[0]. + * $description should be already translated. If $value should appear + * somewhere within the text a `%s` can be used in the translation. + * @param array|null $evolution Optional array containing at least the array keys 'currentValue' and + * 'pastValue' which are needed to calculate the correct percentage. + * An optional 'tooltip' can be set as well. Eg + * array('currentValue' => 10, 'pastValue' => 20, + * 'tooltip' => '10 visits in 2015-07-26 compared to 20 visits in 2015-07-25') + * @param int $order Defines the order. The lower the order the earlier the sparkline will be + * displayed. By default the sparkline will be appended to the end. + * @throws \Exception In case an evolution parameter is set but has wrong data structure + */ + public function addSparkline($requestParamsForSparkline, $value, $description, $evolution = null, $order = null) + { + $metrics = array(); + + if (is_array($value)) { + $values = $value; + } else { + $values = array($value); + } + + if (!is_array($description)) { + $description = array($description); + } + + if (count($values) === count($description)) { + foreach ($values as $index => $value) { + $metrics[] = array( + 'value' => $value, + 'description' => $description[$index] + ); + } + } else { + $msg = 'The number of values and descriptions need to be the same to add a sparkline. '; + $msg .= 'Values: ' . implode(', ', $values). ' Descriptions: ' . implode(', ', $description); + throw new \Exception($msg); + } + + if (empty($metrics)) { + return; + } + + $sparkline = array( + 'url' => $this->getUrlSparkline($requestParamsForSparkline), + 'metrics' => $metrics, + 'order' => $this->getSparklineOrder($order) + ); + + if (!empty($evolution)) { + if (!is_array($evolution) || + !array_key_exists('currentValue', $evolution) || + !array_key_exists('pastValue', $evolution)) { + throw new \Exception('In order to show an evolution in the sparklines view a currentValue and pastValue array key needs to be present'); + } + + $evolutionPercent = CalculateEvolutionFilter::calculate($evolution['currentValue'], $evolution['pastValue'], $precision = 1); + + // do not display evolution if evolution percent is 0 and current value is 0 + if ($evolutionPercent != 0 || $evolution['currentValue'] != 0) { + $sparkline['evolution'] = array( + 'percent' => $evolutionPercent, + 'tooltip' => !empty($evolution['tooltip']) ? $evolution['tooltip'] : null + ); + } + + } + + $this->sparklines[] = $sparkline; + } + + /** + * @return array + * @ignore + */ + public function getSortedSparklines() + { + usort($this->sparklines, function ($a, $b) { + if ($a['order'] == $b['order']) { + return 0; + } + return ($a['order'] < $b['order']) ? -1 : 1; + }); + + return $this->sparklines; + } + + private function getSparklineOrder($order) + { + if (!isset($order)) { + // make sure to append to the end if nothing set (in the order they are added) + $order = 999 + count($this->sparklines); + } + + return (int) $order; + } + + /** + * Returns a URL to a sparkline image for a report served by the current plugin. + * + * The result of this URL should be used with the [sparkline()](/api-reference/Piwik/View#twig) twig function. + * + * The current site ID and period will be used. + * + * @param array $customParameters The array of query parameter name/value pairs that + * should be set in result URL. + * @return string The generated URL. + */ + private function getUrlSparkline($customParameters = array()) + { + $customParameters['viewDataTable'] = 'sparkline'; + + $params = $this->getGraphParamsModified($customParameters); + + // convert array values to comma separated + foreach ($params as &$value) { + if (is_array($value)) { + $value = rawurlencode(implode(',', $value)); + } + } + $url = Url::getCurrentQueryStringWithParametersModified($params); + return $url; + } + + /** + * Returns the array of new processed parameters once the parameters are applied. + * For example: if you set range=last30 and date=2008-03-10, + * the date element of the returned array will be "2008-02-10,2008-03-10" + * + * Parameters you can set: + * - range: last30, previous10, etc. + * - date: YYYY-MM-DD, today, yesterday + * - period: day, week, month, year + * + * @param array $paramsToSet array( 'date' => 'last50', 'viewDataTable' =>'sparkline' ) + * @throws \Piwik\NoAccessException + * @return array + */ + private function getGraphParamsModified($paramsToSet = array()) + { + if (!isset($paramsToSet['period'])) { + $period = Common::getRequestVar('period'); + } else { + $period = $paramsToSet['period']; + } + + if ($period == 'range') { + return $paramsToSet; + } + + if (!isset($paramsToSet['range'])) { + $range = 'last30'; + } else { + $range = $paramsToSet['range']; + } + + if (!isset($paramsToSet['idSite'])) { + $idSite = Common::getRequestVar('idSite'); + } else { + $idSite = $paramsToSet['idSite']; + } + + if (!isset($paramsToSet['date'])) { + $endDate = Common::getRequestVar('date', 'yesterday', 'string'); + } else { + $endDate = $paramsToSet['date']; + } + + $site = new Site($idSite); + + if (is_null($site)) { + throw new NoAccessException("Website not initialized, check that you are logged in and/or using the correct token_auth."); + } + + $paramDate = Range::getRelativeToEndDate($period, $range, $endDate, $site); + + $params = array_merge($paramsToSet, array('date' => $paramDate)); + return $params; + } + +} diff --git a/plugins/CoreVisualizations/javascripts/jqplotEvolutionGraph.js b/plugins/CoreVisualizations/javascripts/jqplotEvolutionGraph.js index 3b62e9197e..b77add4962 100644 --- a/plugins/CoreVisualizations/javascripts/jqplotEvolutionGraph.js +++ b/plugins/CoreVisualizations/javascripts/jqplotEvolutionGraph.js @@ -90,36 +90,7 @@ && typeof self.jqplotParams.axes.xaxis.onclick[lastTick] == 'string') { var url = self.jqplotParams.axes.xaxis.onclick[lastTick]; - if (url && -1 === url.indexOf('#')) { - var module = broadcast.getValueFromHash('module'); - var action = broadcast.getValueFromHash('action'); - var idGoal = broadcast.getValueFromHash('idGoal'); - var idSite = broadcast.getValueFromUrl('idSite', url); - var period = broadcast.getValueFromUrl('period', url); - var date = broadcast.getValueFromUrl('date', url); - - if (module && action) { - url += '#module=' + module + '&action=' + action; - - if (idSite) { - url += '&idSite=' + idSite; - } - - if (idGoal) { - url += '&idGoal=' + idGoal; - } - - if (period) { - url += '&period=' + period; - } - - if (period) { - url += '&date=' + date; - } - } - } - - piwikHelper.redirectToUrl(url); + broadcast.propagateNewPage(url); } }) .on('jqplotPiwikTickOver', function (e, tick) { @@ -161,6 +132,10 @@ render: function () { JqplotGraphDataTablePrototype.render.call(this); + + if (initializeSparklines) { + initializeSparklines(); + } } }); diff --git a/plugins/CoreVisualizations/templates/_dataTableViz_sparklines.twig b/plugins/CoreVisualizations/templates/_dataTableViz_sparklines.twig new file mode 100644 index 0000000000..359c0f9768 --- /dev/null +++ b/plugins/CoreVisualizations/templates/_dataTableViz_sparklines.twig @@ -0,0 +1,31 @@ +{% import '@CoreVisualizations/macros.twig' as macros %} + +{% if not isWidget %} +
+
+{% endif %} + + {% for key, sparkline in sparklines %} + {% if key is even %} + {{ macros.singleSparkline(sparkline) }} + {% endif %} + {% endfor %} + +{% if not isWidget %} +
+
+{% endif %} + + {% for key, sparkline in sparklines %} + {% if key is odd %} + {{ macros.singleSparkline(sparkline) }} + {% endif %} + {% endfor %} + +{% if not isWidget %} +
+
+{% endif %} + +{% include "_sparklineFooter.twig" %} + diff --git a/plugins/CoreVisualizations/templates/macros.twig b/plugins/CoreVisualizations/templates/macros.twig new file mode 100644 index 0000000000..ffd1885be1 --- /dev/null +++ b/plugins/CoreVisualizations/templates/macros.twig @@ -0,0 +1,32 @@ +{% macro singleSparkline(sparkline) %} +
+ {% if sparkline.url %}{{ sparkline(sparkline.url)|raw }}{% endif %} + {% for metric in sparkline.metrics %} + {% if '%s' in metric.description -%} + {{ metric.description|translate(""~metric.value~"")|raw }} + {%- else %} + {{ metric.value }} {{ metric.description }} + {%- endif %}{% if not loop.last %}, {% endif %} + {% endfor %} + {% if sparkline.evolution is defined %} + + {% set evolutionPretty = sparkline.evolution.percent %} + + {% if sparkline.evolution.percent < 0 %} + {% set evolutionClass = 'negative-evolution' %} + {% set evolutionIcon = 'arrow_down.png' %} + {% elseif sparkline.evolution.percent == 0 %} + {% set evolutionClass = 'neutral-evolution' %} + {% set evolutionIcon = 'stop.png' %} + {% else %} + {% set evolutionClass = 'positive-evolution' %} + {% set evolutionIcon = 'arrow_up.png' %} + {% set evolutionPretty = '+' ~ sparkline.evolution.percent %} + {% endif %} + + + {{ evolutionPretty }} + {% endif %} +
+{% endmacro %} diff --git a/plugins/CoreVisualizations/tests/Integration/SparklinesConfigTest.php b/plugins/CoreVisualizations/tests/Integration/SparklinesConfigTest.php new file mode 100644 index 0000000000..3541344f04 --- /dev/null +++ b/plugins/CoreVisualizations/tests/Integration/SparklinesConfigTest.php @@ -0,0 +1,128 @@ +config = new Config(); + } + + public function test_addSparkline_shouldAddAMinimalSparklineWithOneValueAndUseDefaultOrder() + { + $this->config->addSparkline($this->sparklineParams(), $value = 10, $description = 'Visits'); + + $expectedSparkline = array( + 'url' => '?period=day&date=2012-03-06,2012-04-04&idSite=1&module=CoreHome&action=renderMe&viewDataTable=sparkline', + 'metrics' => array ( + array ('value' => 10, 'description' => 'Visits'), + ), + 'order' => 999 + ); + + $this->assertSame(array($expectedSparkline), $this->config->getSortedSparklines()); + } + + public function test_addSparkline_shouldAddSparklineWithMultipleValues() + { + $this->config->addSparkline($this->sparklineParams(), $values = array(10, 20), $description = array('Visits', 'Actions')); + + $sparklines = $this->config->getSortedSparklines(); + + $this->assertSame(array ( + array ('value' => 10, 'description' => 'Visits'), + array ('value' => 20, 'description' => 'Actions'), + ), $sparklines[0]['metrics']); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Values: 10, 20, 30 Descriptions: Visits, Actions + */ + public function test_addSparkline_shouldThrowAnException_IfValuesDoesNotMatchAmountOfDescriptions() + { + $this->config->addSparkline($this->sparklineParams(), $values = array(10, 20, 30), $description = array('Visits', 'Actions')); + } + + public function test_addSparkline_shouldAddEvolution() + { + $evolution = array('currentValue' => 10, 'pastValue' => 21, + 'tooltip' => '1 visit compared to 2 visits'); + $this->config->addSparkline($this->sparklineParams(), $value = 10, $description = 'Visits', $evolution); + + $sparklines = $this->config->getSortedSparklines(); + + $this->assertSame(array ( + 'percent' => '-52.4%', + 'tooltip' => '1 visit compared to 2 visits' + ), $sparklines[0]['evolution']); + } + + public function test_addSparkline_shouldAddOrder() + { + $this->config->addSparkline($this->sparklineParams(), $value = 10, $description = 'Visits', $evolution = null, $order = '42'); + + $sparklines = $this->config->getSortedSparklines(); + + $this->assertSame(42, $sparklines[0]['order']); + } + + public function test_addSparkline_shouldBeAbleToBuildSparklineUrlBasedOnGETparams() + { + $oldGet = $_GET; + $_GET = $this->sparklineParams(); + $this->config->addSparkline(array('columns' => 'nb_visits'), $value = 10, $description = 'Visits'); + $_GET = $oldGet; + + $sparklines = $this->config->getSortedSparklines(); + + $this->assertSame('?columns=nb_visits&viewDataTable=sparkline&date=2012-03-06,2012-04-04', $sparklines[0]['url']); + } + + private function sparklineParams($params = array()) + { + $params['period'] = 'day'; + $params['date'] = '2012-04-04'; + $params['idSite'] = '1'; + $params['module'] = 'CoreHome'; + $params['action'] = 'renderMe'; + + return $params; + } + + public function provideContainerConfig() + { + return array( + 'Piwik\Access' => new FakeAccess() + ); + } +} diff --git a/plugins/CoreVisualizations/tests/Unit/SparklinesConfigTest.php b/plugins/CoreVisualizations/tests/Unit/SparklinesConfigTest.php new file mode 100644 index 0000000000..516f19f8e1 --- /dev/null +++ b/plugins/CoreVisualizations/tests/Unit/SparklinesConfigTest.php @@ -0,0 +1,130 @@ +config = new Config(); + } + + public function test_hasSparklineMetrics_shouldNotHaveSparklineMetrics_ByDefault() + { + $this->assertFalse($this->config->hasSparklineMetrics()); + } + + public function test_hasSparklineMetrics_shouldHaveSparklineMetrics_IfAtLeastOneWasAdded() + { + $this->config->addSparklineMetric('nb_visits'); + + $this->assertTrue($this->config->hasSparklineMetrics()); + } + + public function test_getSparklineMetrics_shouldNotHaveSparklineMetrics_ByDefault() + { + $this->assertSame(array(), $this->config->getSparklineMetrics()); + } + + public function test_addSparklineMetric_getSparklineMetrics_shouldReturnAllAddedSparklineMetrics() + { + $this->addFewSparklines(); + + $this->assertSame(array( + array('columns' => 'nb_visits', 'order' => null), + array('columns' => 'nb_unique_visitors', 'order' => 99), + array('columns' => array('nb_downloads', 'nb_outlinks'), 'order' => null), + ), $this->config->getSparklineMetrics()); + } + + public function test_removeSparklineMetric_shouldRemoveMetric_IfOnlySingleMetricIsGiven() + { + $this->addFewSparklines(); + + $this->config->removeSparklineMetric('nb_unique_visitors'); + + $this->assertSame(array( + array('columns' => 'nb_visits', 'order' => null), + array('columns' => array('nb_downloads', 'nb_outlinks'), 'order' => null), + ), $this->config->getSparklineMetrics()); + } + + public function test_removeSparklineMetric_shouldRemoveMetric_IfMultipleMetricsAreGiven() + { + $this->addFewSparklines(); + + $this->config->removeSparklineMetric(array('nb_downloads', 'nb_outlinks')); + + $this->assertSame(array( + array('columns' => 'nb_visits', 'order' => null), + array('columns' => 'nb_unique_visitors', 'order' => 99), + ), $this->config->getSparklineMetrics()); + } + + public function test_replaceSparklineMetric_shouldBeAbleToReplaceColumns_IfSingleMetricIsGiven() + { + $this->addFewSparklines(); + + $this->config->replaceSparklineMetric('nb_unique_visitors', ''); + + $this->assertSame(array( + array('columns' => 'nb_visits', 'order' => null), + array('columns' => '', 'order' => 99), + array('columns' => array('nb_downloads', 'nb_outlinks'), 'order' => null), + ), $this->config->getSparklineMetrics()); + } + + public function test_replaceSparklineMetric_shouldBeAbleToReplaceColumns_IfMultipleMetricsAreGiven() + { + $this->addFewSparklines(); + + $this->config->replaceSparklineMetric(array('nb_downloads', 'nb_outlinks'), ''); + + $this->assertSame(array( + array('columns' => 'nb_visits', 'order' => null), + array('columns' => 'nb_unique_visitors', 'order' => 99), + array('columns' => '', 'order' => null), + ), $this->config->getSparklineMetrics()); + } + + public function test_addPlaceholder_getSortedSparklines() + { + $this->config->addPlaceholder(); + $this->config->addPlaceholder($order = 10); + $this->config->addPlaceholder(); + $this->config->addPlaceholder($order = 3); + + $this->assertSame(array( + array('url' => '', 'metrics' => array(), 'order' => 3), + array('url' => '', 'metrics' => array(), 'order' => 10), + array('url' => '', 'metrics' => array(), 'order' => 999), + array('url' => '', 'metrics' => array(), 'order' => 1001), + ), $this->config->getSortedSparklines()); + } + + private function addFewSparklines() + { + $this->config->addSparklineMetric('nb_visits'); + $this->config->addSparklineMetric('nb_unique_visitors', 99); + $this->config->addSparklineMetric(array('nb_downloads', 'nb_outlinks')); + } + +} diff --git a/plugins/CustomVariables/Categories/CustomVariablesSubcategory.php b/plugins/CustomVariables/Categories/CustomVariablesSubcategory.php new file mode 100644 index 0000000000..d81b56568c --- /dev/null +++ b/plugins/CustomVariables/Categories/CustomVariablesSubcategory.php @@ -0,0 +1,19 @@ +category = 'General_Visitors'; + $this->categoryId = 'General_Visitors'; } } diff --git a/plugins/CustomVariables/Reports/GetCustomVariables.php b/plugins/CustomVariables/Reports/GetCustomVariables.php index 2ddedc4e97..c6b28b6562 100644 --- a/plugins/CustomVariables/Reports/GetCustomVariables.php +++ b/plugins/CustomVariables/Reports/GetCustomVariables.php @@ -23,8 +23,8 @@ class GetCustomVariables extends Base array('
', '', '')); $this->actionToLoadSubTables = 'getCustomVariablesValuesFromNameId'; $this->order = 10; - $this->widgetTitle = 'CustomVariables_CustomVariables'; - $this->menuTitle = 'CustomVariables_CustomVariables'; + + $this->subcategoryId = 'CustomVariables_CustomVariables'; $this->hasGoalMetrics = true; } diff --git a/plugins/DBStats/Reports/GetMetricDataSummary.php b/plugins/DBStats/Reports/GetMetricDataSummary.php index 92b93fce9b..94735c4e03 100644 --- a/plugins/DBStats/Reports/GetMetricDataSummary.php +++ b/plugins/DBStats/Reports/GetMetricDataSummary.php @@ -11,6 +11,7 @@ namespace Piwik\Plugins\DBStats\Reports; use Piwik\Piwik; use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\CoreVisualizations\Visualizations\Graph; +use Piwik\Plugin\Reports; /** * Shows a datatable that displays the amount of space each numeric archive table @@ -34,7 +35,7 @@ class GetMetricDataSummary extends Base public function getRelatedReports() { return array( - self::factory('DBStats', 'getMetricDataSummaryByYear'), + Reports::factory('DBStats', 'getMetricDataSummaryByYear'), ); } diff --git a/plugins/DBStats/Reports/GetMetricDataSummaryByYear.php b/plugins/DBStats/Reports/GetMetricDataSummaryByYear.php index bc5e8e5c3c..81b89d5d99 100644 --- a/plugins/DBStats/Reports/GetMetricDataSummaryByYear.php +++ b/plugins/DBStats/Reports/GetMetricDataSummaryByYear.php @@ -11,6 +11,7 @@ namespace Piwik\Plugins\DBStats\Reports; use Piwik\Piwik; use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\CoreVisualizations\Visualizations\Graph; +use Piwik\Plugin\Reports; /** * Shows a datatable that displays the amount of space each numeric archive table @@ -35,7 +36,7 @@ class GetMetricDataSummaryByYear extends Base public function getRelatedReports() { return array( - self::factory('DBStats', 'getMetricDataSummary'), + Reports::factory('DBStats', 'getMetricDataSummary'), ); } diff --git a/plugins/DBStats/Reports/GetReportDataSummary.php b/plugins/DBStats/Reports/GetReportDataSummary.php index d38f3ee717..58c1b065c5 100644 --- a/plugins/DBStats/Reports/GetReportDataSummary.php +++ b/plugins/DBStats/Reports/GetReportDataSummary.php @@ -11,6 +11,7 @@ namespace Piwik\Plugins\DBStats\Reports; use Piwik\Piwik; use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\CoreVisualizations\Visualizations\Graph; +use Piwik\Plugin\Reports; /** * Shows a datatable that displays the amount of space each blob archive table @@ -34,7 +35,7 @@ class GetReportDataSummary extends Base public function getRelatedReports() { return array( - self::factory('DBStats', 'getReportDataSummaryByYear'), + Reports::factory('DBStats', 'getReportDataSummaryByYear'), ); } } diff --git a/plugins/DBStats/Reports/GetReportDataSummaryByYear.php b/plugins/DBStats/Reports/GetReportDataSummaryByYear.php index 1bbe67e467..7ff78a638b 100644 --- a/plugins/DBStats/Reports/GetReportDataSummaryByYear.php +++ b/plugins/DBStats/Reports/GetReportDataSummaryByYear.php @@ -11,6 +11,7 @@ namespace Piwik\Plugins\DBStats\Reports; use Piwik\Piwik; use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\CoreVisualizations\Visualizations\Graph; +use Piwik\Plugin\Reports; /** * Shows a datatable that displays the amount of space each blob archive table @@ -35,7 +36,7 @@ class GetReportDataSummaryByYear extends Base public function getRelatedReports() { return array( - self::factory('DBStats', 'getReportDataSummary'), + Reports::factory('DBStats', 'getReportDataSummary'), ); } diff --git a/plugins/Dashboard/API.php b/plugins/Dashboard/API.php index f4637e862a..7bd5bd73a5 100644 --- a/plugins/Dashboard/API.php +++ b/plugins/Dashboard/API.php @@ -8,7 +8,6 @@ namespace Piwik\Plugins\Dashboard; use Piwik\Piwik; -use Piwik\WidgetsList; /** * This API is the Dashboard API: it gives information about dashboards. @@ -43,25 +42,22 @@ class API extends \Piwik\Plugin\API /** * Get the default dashboard. - * - * @return array[] + * @return \array[] */ private function getDefaultDashboard() { $defaultLayout = $this->dashboard->getDefaultLayout(); $defaultLayout = $this->dashboard->decodeLayout($defaultLayout); + $defaultDashboard = array('name' => Piwik::translate('Dashboard_Dashboard'), 'layout' => $defaultLayout, 'iddashboard' => 1); - $defaultDashboard = array('name' => Piwik::translate('Dashboard_Dashboard'), 'layout' => $defaultLayout); - - $widgets = $this->getExistingWidgetsWithinDashboard($defaultDashboard); + $widgets = $this->getVisibleWidgetsWithinDashboard($defaultDashboard); return $this->buildDashboard($defaultDashboard, $widgets); } /** * Get all dashboards which a user has created. - * - * @return array[] + * @return \array[] */ private function getUserDashboards() { @@ -71,17 +67,14 @@ class API extends \Piwik\Plugin\API $dashboards = array(); foreach ($userDashboards as $userDashboard) { - - if ($this->hasDashboardColumns($userDashboard)) { - $widgets = $this->getExistingWidgetsWithinDashboard($userDashboard); - $dashboards[] = $this->buildDashboard($userDashboard, $widgets); - } + $widgets = $this->getVisibleWidgetsWithinDashboard($userDashboard); + $dashboards[] = $this->buildDashboard($userDashboard, $widgets); } return $dashboards; } - private function getExistingWidgetsWithinDashboard($dashboard) + private function getVisibleWidgetsWithinDashboard($dashboard) { $columns = $this->getColumnsFromDashboard($dashboard); @@ -91,7 +84,7 @@ class API extends \Piwik\Plugin\API foreach ($columns as $column) { foreach ($column as $widget) { - if ($this->widgetIsNotHidden($widget) && $this->widgetExists($widget)) { + if ($this->widgetIsNotHidden($widget) && !empty($widget->parameters->module)) { $module = $widget->parameters->module; $action = $widget->parameters->action; @@ -105,39 +98,24 @@ class API extends \Piwik\Plugin\API private function getColumnsFromDashboard($dashboard) { - if (is_array($dashboard['layout'])) { - - return $dashboard['layout']; + if (empty($dashboard['layout'])) { + return array(); } - return $dashboard['layout']->columns; - } - - private function hasDashboardColumns($dashboard) - { if (is_array($dashboard['layout'])) { + return $dashboard['layout']; + } - return !empty($dashboard['layout']); + if (!empty($dashboard['layout']->columns)) { + return $dashboard['layout']->columns; } - return !empty($dashboard['layout']->columns); + return array(); } private function buildDashboard($dashboard, $widgets) { - return array('name' => $dashboard['name'], 'widgets' => $widgets); - } - - private function widgetExists($widget) - { - if (empty($widget->parameters->module)) { - return false; - } - - $module = $widget->parameters->module; - $action = $widget->parameters->action; - - return WidgetsList::isDefined($module, $action); + return array('name' => $dashboard['name'], 'id' => $dashboard['iddashboard'], 'widgets' => $widgets); } private function widgetIsNotHidden($widget) diff --git a/plugins/Dashboard/Categories/DashboardCategory.php b/plugins/Dashboard/Categories/DashboardCategory.php new file mode 100644 index 0000000000..99a3785c84 --- /dev/null +++ b/plugins/Dashboard/Categories/DashboardCategory.php @@ -0,0 +1,17 @@ +setGeneralVariablesView($view); - $view->availableWidgets = json_encode(WidgetsList::get()); $view->availableLayouts = $this->getAvailableLayouts(); $view->dashboardId = Common::getRequestVar('idDashboard', 1, 'int'); - // get the layout via FrontController so controller events are posted - $view->dashboardLayout = FrontController::getInstance()->dispatch('Dashboard', 'getDashboardLayout', - array($checkToken = false)); - return $view; } + // this public function embeddedIndex() { $view = $this->_getDashboardView('@Dashboard/embeddedIndex'); return $view->render(); } + // this is the exported widget public function index() { $view = $this->_getDashboardView('@Dashboard/index'); @@ -70,14 +65,6 @@ class Controller extends \Piwik\Plugin\Controller return $view->render(); } - public function getAvailableWidgets() - { - $this->checkTokenInUrl(); - - Json::sendHeaderJSON(); - return json_encode(WidgetsList::get()); - } - public function getDashboardLayout($checkToken = true) { if ($checkToken) { diff --git a/plugins/Dashboard/Dashboard.php b/plugins/Dashboard/Dashboard.php index 9ccbb822e4..5a0a7cc0ec 100644 --- a/plugins/Dashboard/Dashboard.php +++ b/plugins/Dashboard/Dashboard.php @@ -11,7 +11,8 @@ namespace Piwik\Plugins\Dashboard; use Piwik\Common; use Piwik\Db; use Piwik\Piwik; -use Piwik\WidgetsList; +use Piwik\Category\Subcategory; +use Piwik\Widget\WidgetConfig; /** */ @@ -26,10 +27,43 @@ class Dashboard extends \Piwik\Plugin 'AssetManager.getJavaScriptFiles' => 'getJsFiles', 'AssetManager.getStylesheetFiles' => 'getStylesheetFiles', 'UsersManager.deleteUser' => 'deleteDashboardLayout', - 'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys' + 'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys', + 'Widget.addWidgetConfigs' => 'addWidgetConfigs', + 'Category.addSubcategories' => 'addSubcategories' ); } + public function addWidgetConfigs(&$widgets) + { + $dashboards = API::getInstance()->getDashboards(); + + foreach ($dashboards as $dashboard) { + $config = new WidgetConfig(); + $config->setIsNotWidgetizable(); + $config->setModule('Dashboard'); + $config->setAction('embeddedIndex'); + $config->setCategoryId('Dashboard_Dashboard'); + $config->setSubcategoryId($dashboard['id']); + $config->setParameters(array('idDashboard' => $dashboard['id'])); + $widgets[] = $config; + } + } + + public function addSubcategories(&$subcategories) + { + $dashboards = API::getInstance()->getDashboards(); + + $order = 0; + foreach ($dashboards as $dashboard) { + $subcategory = new Subcategory(); + $subcategory->setName($dashboard['name']); + $subcategory->setCategoryId('Dashboard_Dashboard'); + $subcategory->setId($dashboard['id']); + $subcategory->setOrder($order++); + $subcategories[] = $subcategory; + } + } + /** * Returns the layout in the DB for the given user, or false if the layout has not been set yet. * Parameters must be checked BEFORE this function call @@ -70,14 +104,14 @@ class Dashboard extends \Piwik\Plugin $defaultLayout = '[ [ - {"uniqueId":"widgetVisitsSummarygetEvolutionGraphcolumnsArray","parameters":{"module":"VisitsSummary","action":"getEvolutionGraph","columns":"nb_visits"}}, + {"uniqueId":"widgetVisitsSummarygetEvolutionGraphforceView1viewDataTablegraphEvolution","parameters":{"forceView":"1","viewDataTable":"graphEvolution","module":"VisitsSummary","action":"getEvolutionGraph"}}, {"uniqueId":"widgetLivewidget","parameters":{"module":"Live","action":"widget"}}, - {"uniqueId":"widgetVisitorInterestgetNumberOfVisitsPerVisitDuration","parameters":{"module":"VisitorInterest","action":"getNumberOfVisitsPerVisitDuration"}} + {"uniqueId":"widgetVisitorInterestgetNumberOfVisitsPerVisitDurationviewDataTablecloud","parameters":{"viewDataTable":"cloud","module":"VisitorInterest","action":"getNumberOfVisitsPerVisitDuration"}} ], [ ' . $topWidget . ' {"uniqueId":"widgetReferrersgetWebsites","parameters":{"module":"Referrers","action":"getWebsites"}}, - {"uniqueId":"widgetVisitTimegetVisitInformationPerServerTime","parameters":{"module":"VisitTime","action":"getVisitInformationPerServerTime"}} + {"uniqueId":"widgetVisitTimegetVisitInformationPerServerTimeviewDataTablegraphVerticalBar","parameters":{"viewDataTable": "graphVerticalBar","module":"VisitTime","action":"getVisitInformationPerServerTime"}} ], [ {"uniqueId":"widgetUserCountryMapvisitorMap","parameters":{"module":"UserCountryMap","action":"visitorMap"}}, @@ -160,24 +194,6 @@ class Dashboard extends \Piwik\Plugin ); } - foreach ($layoutObject->columns as &$row) { - if (!is_array($row)) { - $row = array(); - continue; - } - - foreach ($row as $widgetId => $widget) { - if (isset($widget->parameters->module)) { - $controllerName = $widget->parameters->module; - $controllerAction = $widget->parameters->action; - if (!WidgetsList::isDefined($controllerName, $controllerAction)) { - unset($row[$widgetId]); - } - } else { - unset($row[$widgetId]); - } - } - } $layout = $this->encodeLayout($layoutObject); return $layout; } @@ -202,11 +218,13 @@ class Dashboard extends \Piwik\Plugin public function getJsFiles(&$jsFiles) { + $jsFiles[] = "plugins/Dashboard/angularjs/common/services/dashboards-model.js"; $jsFiles[] = "plugins/Dashboard/javascripts/widgetMenu.js"; $jsFiles[] = "libs/javascript/json2.js"; $jsFiles[] = "plugins/Dashboard/javascripts/dashboardObject.js"; $jsFiles[] = "plugins/Dashboard/javascripts/dashboardWidget.js"; $jsFiles[] = "plugins/Dashboard/javascripts/dashboard.js"; + $jsFiles[] = "plugins/Dashboard/angularjs/dashboard/dashboard.directive.js"; } public function getStylesheetFiles(&$stylesheets) diff --git a/plugins/Dashboard/Menu.php b/plugins/Dashboard/Menu.php index f90c117e10..7967635f97 100644 --- a/plugins/Dashboard/Menu.php +++ b/plugins/Dashboard/Menu.php @@ -9,7 +9,6 @@ namespace Piwik\Plugins\Dashboard; use Piwik\Db; -use Piwik\Menu\MenuReporting; use Piwik\Menu\MenuTop; use Piwik\Piwik; use Piwik\Plugins\UsersManager\UserPreferences; @@ -19,24 +18,6 @@ use Piwik\Site; */ class Menu extends \Piwik\Plugin\Menu { - public function configureReportingMenu(MenuReporting $menu) - { - $menu->addItem('Dashboard_Dashboard', '', $this->urlForAction('embeddedIndex', array('idDashboard' => 1)), 5); - - if (!Piwik::isUserIsAnonymous()) { - $login = Piwik::getCurrentUserLogin(); - - $dashboard = new Dashboard(); - $dashboards = $dashboard->getAllDashboards($login); - - $pos = 0; - foreach ($dashboards as $dashboard) { - $menu->addItem('Dashboard_Dashboard', $dashboard['name'], $this->urlForAction('embeddedIndex', array('idDashboard' => $dashboard['iddashboard'])), $pos); - $pos++; - } - } - } - public function configureTopMenu(MenuTop $menu) { $userPreferences = new UserPreferences(); diff --git a/plugins/Dashboard/Model.php b/plugins/Dashboard/Model.php index 790076c1a9..0ef02aeea9 100644 --- a/plugins/Dashboard/Model.php +++ b/plugins/Dashboard/Model.php @@ -10,7 +10,7 @@ namespace Piwik\Plugins\Dashboard; use Piwik\Common; use Piwik\Db; use Piwik\DbHelper; -use Piwik\WidgetsList; +use Piwik\Widget\WidgetsList; class Model { @@ -189,7 +189,11 @@ class Model if ($widget->uniqueId == $oldWidgetId) { - $newWidgetId = WidgetsList::getWidgetUniqueId($newWidget['module'], $newWidget['action'], $newWidget['params']); + if (!empty($newWidget['uniqueId'])) { + $newWidgetId = $newWidget['uniqueId']; + } else { + $newWidgetId = WidgetsList::getWidgetUniqueId($newWidget['module'], $newWidget['action'], $newWidget['params']); + } // is new widget already is on dashboard just remove the old one if (self::layoutContainsWidget($dashboardLayout, $newWidgetId)) { diff --git a/plugins/Dashboard/angularjs/common/services/dashboards-model.js b/plugins/Dashboard/angularjs/common/services/dashboards-model.js new file mode 100644 index 0000000000..e0d861c2ba --- /dev/null +++ b/plugins/Dashboard/angularjs/common/services/dashboards-model.js @@ -0,0 +1,68 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ +(function () { + angular.module('piwikApp.service').factory('dashboardsModel', dashboardsModel); + + dashboardsModel.$inject = ['piwikApi']; + + function dashboardsModel (piwikApi) { + + var dashboardsPromise = null; + + var model = { + dashboards: [], + getAllDashboards: getAllDashboards, + reloadAllDashboards: reloadAllDashboards, + getDashboard: getDashboard, + getDashboardLayout: getDashboardLayout + }; + + return model; + + function getDashboard(dashboardId) + { + return getAllDashboards().then(function (dashboards) { + var dashboard = null; + angular.forEach(dashboards, function (board) { + if (parseInt(board.id, 10) === parseInt(dashboardId, 10)) { + dashboard = board; + } + }); + return dashboard; + }); + } + + function getDashboardLayout(dashboardId) + { + return piwikApi.fetch({module: 'Dashboard', action: 'getDashboardLayout', idDashboard: dashboardId}); + } + + function reloadAllDashboards() + { + if (dashboardsPromise) { + dashboardsPromise = null; + } + + return getAllDashboards(); + } + + function getAllDashboards() + { + if (!dashboardsPromise) { + dashboardsPromise = piwikApi.fetch({method: 'Dashboard.getDashboards'}).then(function (response) { + if (response) { + model.dashboards = response; + } + + return response; + }); + } + + return dashboardsPromise; + } + } +})(); \ No newline at end of file diff --git a/plugins/Dashboard/angularjs/dashboard/dashboard.directive.js b/plugins/Dashboard/angularjs/dashboard/dashboard.directive.js new file mode 100644 index 0000000000..578737940c --- /dev/null +++ b/plugins/Dashboard/angularjs/dashboard/dashboard.directive.js @@ -0,0 +1,103 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +/** + *
+ */ +(function () { + angular.module('piwikApp').directive('piwikDashboard', piwikDashboard); + + piwikDashboard.$inject = ['dashboardsModel', '$rootScope', '$q']; + + function piwikDashboard(dashboardsModel, $rootScope, $q) { + + function renderDashboard(dashboardId, dashboard, layout) + { + $('.dashboardSettings').show(); + initTopControls(); + + // Embed dashboard + if (!$('#topBars').length) { + $('.dashboardSettings').after($('#Dashboard')); + $('#Dashboard_embeddedIndex_' + dashboardId).addClass('sfHover'); + } + + widgetsHelper.getAvailableWidgets(); + + $('#dashboardWidgetsArea') + .on('dashboardempty', showEmptyDashboardNotification) + .dashboard({ + idDashboard: dashboardId, + layout: layout, + name: dashboard ? dashboard.name : '' + }); + + $('#columnPreview').find('>div').each(function () { + var width = []; + $('div', this).each(function () { + width.push(this.className.replace(/width-/, '')); + }); + $(this).attr('layout', width.join('-')); + }); + + $('#columnPreview').find('>div').on('click', function () { + $('#columnPreview').find('>div').removeClass('choosen'); + $(this).addClass('choosen'); + }); + } + + function fetchDashboard(dashboardId) { + $('#dashboardWidgetsArea').innerHTML =''; + + var getDashboard = dashboardsModel.getDashboard(dashboardId); + var getLayout = dashboardsModel.getDashboardLayout(dashboardId); + + $q.all([getDashboard, getLayout]).then(function (response) { + var dashboard = response[0]; + var layout = response[1]; + + $(function() { + renderDashboard(dashboardId, dashboard, layout); + }); + }); + } + + function clearDashboard () { + $('.top_controls .dashboard-manager').hide(); + $('#dashboardWidgetsArea').dashboard('destroy'); + } + + return { + restrict: 'A', + scope: { + dashboardid: '=', + layout: '=' + }, + link: function (scope, element, attrs) { + + scope.$parent.fetchDashboard = function (dashboardId) { + scope.dashboardId = dashboardId; + fetchDashboard(dashboardId) + }; + + fetchDashboard(scope.dashboardid); + + function onLocationChange(event, url1, url2) + { + if (url1 !== url2) { + clearDashboard(); + } + } + + // should be rather handled in route or so. + var unbind = $rootScope.$on('$locationChangeSuccess', onLocationChange); + scope.$on('$destroy', onLocationChange); + scope.$on('$destroy', unbind); + } + }; + } +})(); \ No newline at end of file diff --git a/plugins/Dashboard/javascripts/dashboard.js b/plugins/Dashboard/javascripts/dashboard.js index 238aca5197..f78814cdbb 100644 --- a/plugins/Dashboard/javascripts/dashboard.js +++ b/plugins/Dashboard/javascripts/dashboard.js @@ -5,45 +5,12 @@ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later */ -function initDashboard(dashboardId, dashboardLayout) { - - $('.dashboardSettings').show(); - initTopControls(); - - // Embed dashboard - if (!$('#topBars').length) { - $('.dashboardSettings').after($('#Dashboard')); - $('#Dashboard_embeddedIndex_' + dashboardId).addClass('sfHover'); - } - - widgetsHelper.getAvailableWidgets(); - - $('#dashboardWidgetsArea') - .on('dashboardempty', showEmptyDashboardNotification) - .dashboard({ - idDashboard: dashboardId, - layout: dashboardLayout - }); - - $('#columnPreview').find('>div').each(function () { - var width = []; - $('div', this).each(function () { - width.push(this.className.replace(/width-/, '')); - }); - $(this).attr('layout', width.join('-')); - }); - - $('#columnPreview').find('>div').on('click', function () { - $('#columnPreview').find('>div').removeClass('choosen'); - $(this).addClass('choosen'); - }); -} - function createDashboard() { - $('#createDashboardName').val(''); - piwikHelper.modalConfirm('#createDashboardConfirm', {yes: function () { - var dashboardName = $('#createDashboardName').val(); - var type = ($('#dashboard_type_empty:checked').length > 0) ? 'empty' : 'default'; + $(makeSelectorLastId('createDashboardName')).val(''); + + piwikHelper.modalConfirm(makeSelectorLastId('createDashboardConfirm'), {yes: function () { + var dashboardName = $(makeSelectorLastId('createDashboardName')).val(); + var type = ($('[id=dashboard_type_empty]:last:checked').length > 0) ? 'empty' : 'default'; var ajaxRequest = new ajaxHelper(); ajaxRequest.setLoadingElement(); @@ -57,50 +24,74 @@ function createDashboard() { }, 'post'); ajaxRequest.setCallback( function (id) { - $('#dashboardWidgetsArea').dashboard('loadDashboard', id); + angular.element(document).injector().invoke(function ($location, reportingMenuModel, dashboardsModel) { + dashboardsModel.reloadAllDashboards().then(function () { + $('#dashboardWidgetsArea').dashboard('loadDashboard', id); + $('#dashboardWidgetsArea').dashboard('rebuildMenu'); + }); + }); } ); ajaxRequest.send(true); }}); } +function makeSelectorLastId(domElementId) +{ + // there can be many elements with this id, we prefer the last one + return '[id=' + domElementId + ']:last'; +} + function resetDashboard() { - piwikHelper.modalConfirm('#resetDashboardConfirm', {yes: function () { $('#dashboardWidgetsArea').dashboard('resetLayout'); }}); + piwikHelper.modalConfirm(makeSelectorLastId('resetDashboardConfirm'), {yes: + function () { $('#dashboardWidgetsArea').dashboard('resetLayout'); + }}); } function renameDashboard() { - $('#newDashboardName').val($('#dashboardWidgetsArea').dashboard('getDashboardName')); - piwikHelper.modalConfirm('#renameDashboardConfirm', {yes: function () { $('#dashboardWidgetsArea').dashboard('setDashboardName', $('#newDashboardName').val()); }}); + $(makeSelectorLastId('newDashboardName')).val($('#dashboardWidgetsArea').dashboard('getDashboardName')); + + piwikHelper.modalConfirm(makeSelectorLastId('renameDashboardConfirm'), {yes: function () { + var newDashboardName = $(makeSelectorLastId('newDashboardName')).val(); + $('#dashboardWidgetsArea').dashboard('setDashboardName', newDashboardName); + }}); } function removeDashboard() { - $('#removeDashboardConfirm').find('h2 span').text($('#dashboardWidgetsArea').dashboard('getDashboardName')); - piwikHelper.modalConfirm('#removeDashboardConfirm', {yes: function () { $('#dashboardWidgetsArea').dashboard('removeDashboard'); }}); + $(makeSelectorLastId('removeDashboardConfirm')).find('h2 span').text($('#dashboardWidgetsArea').dashboard('getDashboardName')); + + piwikHelper.modalConfirm(makeSelectorLastId('removeDashboardConfirm'), {yes: function () { + $('#dashboardWidgetsArea').dashboard('removeDashboard'); + }}); } function showChangeDashboardLayoutDialog() { $('#columnPreview').find('>div').removeClass('choosen'); $('#columnPreview').find('>div[layout=' + $('#dashboardWidgetsArea').dashboard('getColumnLayout') + ']').addClass('choosen'); - piwikHelper.modalConfirm('#changeDashboardLayout', {yes: function () { - $('#dashboardWidgetsArea').dashboard('setColumnLayout', $('#changeDashboardLayout').find('.choosen').attr('layout')); + + var id = makeSelectorLastId('changeDashboardLayout'); + piwikHelper.modalConfirm(id, {yes: function () { + $('#dashboardWidgetsArea').dashboard('setColumnLayout', $(id).find('.choosen').attr('layout')); }}); } function showEmptyDashboardNotification() { - piwikHelper.modalConfirm('#dashboardEmptyNotification', { + piwikHelper.modalConfirm(makeSelectorLastId('dashboardEmptyNotification'), { resetDashboard: function () { $('#dashboardWidgetsArea').dashboard('resetLayout'); }, addWidget: function () { $('.dashboardSettings').trigger('click'); } }); } function setAsDefaultWidgets() { - piwikHelper.modalConfirm('#setAsDefaultWidgetsConfirm', { - yes: function () { $('#dashboardWidgetsArea').dashboard('saveLayoutAsDefaultWidgetLayout'); } + piwikHelper.modalConfirm(makeSelectorLastId('setAsDefaultWidgetsConfirm'), { + yes: function () { + $('#dashboardWidgetsArea').dashboard('saveLayoutAsDefaultWidgetLayout'); + } }); } function copyDashboardToUser() { - $('#copyDashboardName').val($('#dashboardWidgetsArea').dashboard('getDashboardName')); + $(makeSelectorLastId('copyDashboardName')).val($('#dashboardWidgetsArea').dashboard('getDashboardName')); var ajaxRequest = new ajaxHelper(); ajaxRequest.addParams({ module: 'API', @@ -109,13 +100,13 @@ function copyDashboardToUser() { }, 'get'); ajaxRequest.setCallback( function (availableUsers) { - $('#copyDashboardUser').empty(); - $('#copyDashboardUser').append( + $(makeSelectorLastId('copyDashboardUser')).empty(); + $(makeSelectorLastId('copyDashboardUser')).append( $('').val(piwik.userLogin).text(piwik.userLogin) ); $.each(availableUsers, function (index, user) { if (user.login != 'anonymous' && user.login != piwik.userLogin) { - $('#copyDashboardUser').append( + $(makeSelectorLastId('copyDashboardUser')).append( $('').val(user.login).text(user.login + ' (' + user.alias + ')') ); } @@ -124,10 +115,10 @@ function copyDashboardToUser() { ); ajaxRequest.send(true); - piwikHelper.modalConfirm('#copyDashboardToUserConfirm', { + piwikHelper.modalConfirm(makeSelectorLastId('copyDashboardToUserConfirm'), { yes: function () { - var copyDashboardName = $('#copyDashboardName').val(); - var copyDashboardUser = $('#copyDashboardUser').val(); + var copyDashboardName = $(makeSelectorLastId('copyDashboardName')).val(); + var copyDashboardUser = $(makeSelectorLastId('copyDashboardUser')).val(); var ajaxRequest = new ajaxHelper(); ajaxRequest.addParams({ @@ -291,7 +282,7 @@ function copyDashboardToUser() { }, isWidgetAvailable: function (widgetUniqueId) { - return !$('#dashboardWidgetsArea').find('[widgetId=' + widgetUniqueId + ']').length; + return !$('#dashboardWidgetsArea').find('[widgetId="' + widgetUniqueId + '"]').length; }, widgetSelected: function (widget) { @@ -301,6 +292,7 @@ function copyDashboardToUser() { DashboardManagerControl.initElements = function () { UIControl.initElements(this, '.dashboard-manager'); + $('.top_controls .dashboard-manager').hide(); // initially hide the manager }; exports.DashboardManagerControl = DashboardManagerControl; diff --git a/plugins/Dashboard/javascripts/dashboardObject.js b/plugins/Dashboard/javascripts/dashboardObject.js index 7808d22c11..08bb36dd79 100644 --- a/plugins/Dashboard/javascripts/dashboardObject.js +++ b/plugins/Dashboard/javascripts/dashboardObject.js @@ -57,9 +57,6 @@ if (options.layout) { generateLayout(options.layout); - buildMenu(); - } else { - methods.loadDashboard.apply(this, [dashboardId]); } return this; @@ -89,11 +86,11 @@ dashboardName = ''; dashboardLayout = null; dashboardId = dashboardIdToLoad; - piwikHelper.showAjaxLoading(); - broadcast.updateHashOnly = true; - broadcast.propagateAjax('?idDashboard=' + dashboardIdToLoad); - fetchLayout(generateLayout); - buildMenu(); + + var element = $('[piwik-dashboard]'); + var scope = angular.element(element).scope(); + scope.fetchDashboard(dashboardIdToLoad); + return this; }, @@ -179,6 +176,8 @@ ajaxRequest.send(true); }, + rebuildMenu: rebuildMenu, + /** * Removes the current dashboard */ @@ -201,6 +200,39 @@ } }; + function removeNonExistingWidgets(availableWidgets, layout) + { + var existingModuleAction = {}; + $.each(availableWidgets, function (category, widgets) { + $.each(widgets, function (index, widget) { + existingModuleAction[widget.module + '.' + widget.action] = true; + }); + }); + + var columns = []; + $.each(layout.columns, function (i, column) { + var widgets = []; + + $.each(column, function (j, widget) { + if (!widget.parameters || !widget.parameters.module) { + return; + } + + var method = widget.parameters.module + '.' + widget.parameters.action + if (existingModuleAction[method]) { + widgets.push(widget); + } + + }); + + columns[i] = widgets; + }); + + layout.columns = columns; + + return layout; + } + /** * Generates the dashboard out of the given layout * @@ -209,46 +241,33 @@ function generateLayout(layout) { dashboardLayout = parseLayout(layout); - piwikHelper.hideAjaxLoading(); - adjustDashboardColumns(dashboardLayout.config.layout); - - var dashboardContainsWidgets = false; - for (var column = 0; column < dashboardLayout.columns.length; column++) { - for (var i in dashboardLayout.columns[column]) { - if (typeof dashboardLayout.columns[column][i] != 'object') { - // Fix IE8 bug: the "i in" loop contains i="indexOf", which would yield type function. - // If we would continue with i="indexOf", an invalid widget would be created. - continue; + + widgetsHelper.getAvailableWidgets(function (availableWidgets) { + dashboardLayout = removeNonExistingWidgets(availableWidgets, dashboardLayout); + + piwikHelper.hideAjaxLoading(); + adjustDashboardColumns(dashboardLayout.config.layout); + + var dashboardContainsWidgets = false; + for (var column = 0; column < dashboardLayout.columns.length; column++) { + for (var i in dashboardLayout.columns[column]) { + if (typeof dashboardLayout.columns[column][i] != 'object') { + // Fix IE8 bug: the "i in" loop contains i="indexOf", which would yield type function. + // If we would continue with i="indexOf", an invalid widget would be created. + continue; + } + var widget = dashboardLayout.columns[column][i]; + dashboardContainsWidgets = true; + addWidgetTemplate(widget.uniqueId, column + 1, widget.parameters, false, widget.isHidden) } - var widget = dashboardLayout.columns[column][i]; - dashboardContainsWidgets = true; - addWidgetTemplate(widget.uniqueId, column + 1, widget.parameters, false, widget.isHidden) } - } - - if (!dashboardContainsWidgets) { - $(dashboardElement).trigger('dashboardempty'); - } - makeWidgetsSortable(); - } + if (!dashboardContainsWidgets) { + $(dashboardElement).trigger('dashboardempty'); + } - /** - * Fetches the layout for the currently set dashboard id - * and passes the response to given callback function - * - * @param {function} callback - */ - function fetchLayout(callback) { - globalAjaxQueue.abort(); - var ajaxRequest = new ajaxHelper(); - ajaxRequest.addParams({ - module: 'Dashboard', - action: 'getDashboardLayout', - idDashboard: dashboardId - }, 'get'); - ajaxRequest.setCallback(callback); - ajaxRequest.send(false); + makeWidgetsSortable(); + }); } /** @@ -388,7 +407,7 @@ * @param {String} uniqueId */ function reloadWidget(uniqueId) { - $('[widgetId=' + uniqueId + ']', dashboardElement).dashboardWidget('reload', false, true); + $('[widgetId="' + uniqueId + '"]', dashboardElement).dashboardWidget('reload', false, true); } /** @@ -417,7 +436,7 @@ $('.col:nth-child(' + columnNumber + ')', dashboardElement).append(widgetContent); } - $('[widgetId=' + uniqueId + ']', dashboardElement).dashboardWidget({ + $('[widgetId="' + uniqueId + '"]', dashboardElement).dashboardWidget({ uniqueId: uniqueId, widgetParameters: widgetParameters, onChange: function () { @@ -468,7 +487,19 @@ /** * Handle clicks for menu items for choosing between available dashboards */ - function buildMenu() { + function rebuildMenu() { + + if ($('[piwik-reporting-menu]').length) { + // dashboard in reporting page (regular Piwik UI) + angular.element(document).injector().invoke(function (reportingMenuModel) { + reportingMenuModel.reloadMenuItems(); + }); + return; + } + + var _self = this; + + // widgetized var success = function (dashboards) { var dashboardMenuList = $('#Dashboard').find('> ul'); var dashboardMenuListItems = dashboardMenuList.find('>li'); @@ -484,7 +515,7 @@ for (var i = 0; i < dashboards.length; i++) { var $link = $('').attr('data-idDashboard', dashboards[i].iddashboard).text(dashboards[i].name); var $li = $('
  • ').attr('id', 'Dashboard_embeddedIndex_' + dashboards[i].iddashboard) - .addClass('dashboardMenuItem').append($link); + .addClass('dashboardMenuItem').append($link); items.push($li); if (dashboards[i].iddashboard == dashboardId) { @@ -502,15 +533,10 @@ var idDashboard = $(this).attr('data-idDashboard'); - if (typeof piwikMenu != 'undefined') { - piwikMenu.activateMenu('Dashboard', 'embeddedIndex'); - } $('#Dashboard ul li').removeClass('sfHover'); - if ($(dashboardElement).length) { - $(dashboardElement).dashboard('loadDashboard', idDashboard); - } else { - broadcast.propagateAjax('module=Dashboard&action=embeddedIndex&idDashboard=' + idDashboard); - } + + methods.loadDashboard.apply(_self, [idDashboard]); + $(this).closest('li').addClass('sfHover'); }); }; @@ -521,7 +547,7 @@ action: 'getAllDashboards' }, 'get'); ajaxRequest.setCallback(success); - ajaxRequest.send(false); + ajaxRequest.send(); } /** @@ -568,7 +594,7 @@ function () { if (dashboardChanged) { dashboardChanged = false; - buildMenu(); + rebuildMenu(); } } ); @@ -594,6 +620,7 @@ }, 'get'); ajaxRequest.setCallback( function () { + rebuildMenu(); methods.loadDashboard.apply(this, [1]); } ); diff --git a/plugins/Dashboard/javascripts/dashboardWidget.js b/plugins/Dashboard/javascripts/dashboardWidget.js index accd0aa2c2..969ed9db28 100755 --- a/plugins/Dashboard/javascripts/dashboardWidget.js +++ b/plugins/Dashboard/javascripts/dashboardWidget.js @@ -70,7 +70,7 @@ */ destroy: function () { if (this.isMaximised) { - $('[widgetId=' + this.uniqueId + ']').dialog('destroy'); + $('[widgetId="' + this.uniqueId + '"]').dialog('destroy'); } $('*', this.element).off('.dashboardWidget'); // unbind all events $('.widgetContent', this.element).trigger('widget:destroy'); @@ -197,7 +197,7 @@ var emptyWidgetContent = require('piwik/UI/Dashboard').WidgetFactory.make(uniqueId, title); this.element.html(emptyWidgetContent); - var widgetElement = $('#' + uniqueId, this.element); + var widgetElement = $('[id="' + uniqueId + '"]', this.element); var self = this; widgetElement .on('mouseenter.dashboardWidget', function () { @@ -312,7 +312,7 @@ } $('body').off('.dashboardWidget'); $(this).dialog("destroy"); - $('#' + self.uniqueId + '-placeholder').replaceWith(this); + $('[id="' + self.uniqueId + '-placeholder"]').replaceWith(this); $(this).removeAttr('style'); self.options.onChange(); $(this).find('div.piwik-graph').trigger('resizeGraph'); @@ -339,6 +339,9 @@ */ detachWidget: function () { this.element.before('
    '); + var placeholder = $('[id="' + self.uniqueId + '-placeholder"]') + + $('#' + this.uniqueId + '-placeholder').height(this.element.height()); $('#' + this.uniqueId + '-placeholder').width(this.element.width() - 16); diff --git a/plugins/Dashboard/javascripts/widgetMenu.js b/plugins/Dashboard/javascripts/widgetMenu.js index 6d58415cb9..169768eb03 100644 --- a/plugins/Dashboard/javascripts/widgetMenu.js +++ b/plugins/Dashboard/javascripts/widgetMenu.js @@ -13,21 +13,82 @@ function widgetsHelper() { * * @return {object} object containing available widgets */ -widgetsHelper.getAvailableWidgets = function () { +widgetsHelper.getAvailableWidgets = function (callback) { + + function mergeCategoriesAndSubCategories(availableWidgets) + { + var categorized = {}; + + $.each(availableWidgets, function (index, widget) { + var category = widget.category.name; + + if (!categorized[category]) { + categorized[category] = {'-': []}; + } + + var subcategory = '-'; + if (widget.subcategory && widget.subcategory.name) { + subcategory = widget.subcategory.name; + } + + if (!categorized[category][subcategory]) { + categorized[category][subcategory] = []; + } + + categorized[category][subcategory].push(widget); + }); + + var moved = {}; + + $.each(categorized, function (category, widgets) { + $.each(widgets, function (subcategory, subwidgets) { + + var categoryToUse = category; + if (subwidgets.length >= 3 && subcategory !== '-') { + categoryToUse = category + ' - ' + subcategory; + } + + if (!moved[categoryToUse]) { + moved[categoryToUse] = []; + } + + $.each(subwidgets, function (index, widget) { + moved[categoryToUse].push(widget); + }); + }); + }); + + return moved; + } + if (!widgetsHelper.availableWidgets) { var ajaxRequest = new ajaxHelper(); + ajaxRequest._mixinDefaultGetParams = function (params) { + return params; + }; ajaxRequest.addParams({ - module: 'Dashboard', - action: 'getAvailableWidgets' + module: 'API', + method: 'API.getWidgetMetadata', + format: 'JSON', + deep: '1', + idSite: piwik.idSite || broadcast.getValueFromUrl('idSite') }, 'get'); ajaxRequest.setCallback( function (data) { - widgetsHelper.availableWidgets = data; + widgetsHelper.availableWidgets = mergeCategoriesAndSubCategories(data); + + if (callback) { + callback(widgetsHelper.availableWidgets); + } } ); ajaxRequest.send(true); } + if (callback) { + callback(widgetsHelper.availableWidgets); + } + return widgetsHelper.availableWidgets; }; @@ -191,6 +252,7 @@ widgetsHelper.loadWidgetAjax = function (widgetUniqueId, widgetParameters, onWid * @return {$} category list element */ function createWidgetCategoryList(widgetPreview, availableWidgets) { + var settings = widgetPreview.settings; if (!$('.' + settings.categorylistClass, widgetPreview).length) { @@ -200,7 +262,6 @@ widgetsHelper.loadWidgetAjax = function (widgetUniqueId, widgetParameters, onWid } for (var widgetCategory in availableWidgets) { - $('.' + settings.categorylistClass, widgetPreview).append('
  • ' + widgetCategory + '
  • '); } @@ -257,6 +318,8 @@ widgetsHelper.loadWidgetAjax = function (widgetUniqueId, widgetParameters, onWid widgetClass += ' ' + settings.unavailableClass; } + widgetName = piwikHelper.escape(piwikHelper.htmlEntities(widgetName)); + widgetList.append('
  • ' + widgetName + '
  • '); } @@ -278,7 +341,7 @@ widgetsHelper.loadWidgetAjax = function (widgetUniqueId, widgetParameters, onWid clearTimeout(widgetPreview); }); - $('li:not(.' + settings.unavailableClass + ')', widgetList).on('click', function () { + $('li', widgetList).on('click', function () { if (!$('.widgetLoading', widgetPreview).length) { settings.onSelect($(this).attr('uniqueid')); if (settings.resetOnSelect) { @@ -317,7 +380,7 @@ widgetsHelper.loadWidgetAjax = function (widgetUniqueId, widgetParameters, onWid */ function showPreview(widgetUniqueId, widgetPreview) { // do not reload id widget already displayed - if ($('#' + widgetUniqueId, widgetPreview).length) return; + if ($('[id="' + widgetUniqueId + '"]', widgetPreview).length) return; var settings = widgetPreview.settings; @@ -335,7 +398,8 @@ widgetsHelper.loadWidgetAjax = function (widgetUniqueId, widgetParameters, onWid previewElement.html(emptyWidgetHtml); var onWidgetLoadedCallback = function (response) { - var widgetElement = $('#' + widgetUniqueId); + var widgetElement = $(document.getElementById(widgetUniqueId)); + // document.getElementById needed for widgets with uniqueid like widgetOpens+Contact+Form $('.widgetContent', widgetElement).html($(response)); $('.widgetContent', widgetElement).trigger('widget:create'); settings.onPreviewLoaded(widgetUniqueId, widgetElement); @@ -398,19 +462,21 @@ widgetsHelper.loadWidgetAjax = function (widgetUniqueId, widgetParameters, onWid this.onPreviewLoaded = this.settings.onPreviewLoaded; } - availableWidgets = widgetsHelper.getAvailableWidgets(); + var self = this; + widgetsHelper.getAvailableWidgets(function (availableWidgets) { - var categoryList = createWidgetCategoryList(this, availableWidgets); + var categoryList = createWidgetCategoryList(self, availableWidgets); - var self = this; - $('li', categoryList).on('mouseover', function () { - var category = $(this).text(); - var widgets = availableWidgets[category]; - $('li', categoryList).removeClass(self.settings.choosenClass); - $(this).addClass(self.settings.choosenClass); - showWidgetList(widgets, self); - createPreviewElement(self); // empty preview + $('li', categoryList).on('mouseover', function () { + var category = $(this).text(); + var widgets = availableWidgets[category]; + $('li', categoryList).removeClass(self.settings.choosenClass); + $(this).addClass(self.settings.choosenClass); + showWidgetList(widgets, self); + createPreviewElement(self); // empty preview + }); }); + }; } }); diff --git a/plugins/Dashboard/templates/embeddedIndex.twig b/plugins/Dashboard/templates/embeddedIndex.twig index af1dbeb887..a7633ca193 100644 --- a/plugins/Dashboard/templates/embeddedIndex.twig +++ b/plugins/Dashboard/templates/embeddedIndex.twig @@ -1,10 +1,4 @@ - -
    +

    {{ 'Dashboard_DeleteWidgetConfirm'|translate }}

    diff --git a/plugins/DevicePlugins/Reports/Base.php b/plugins/DevicePlugins/Reports/Base.php index 81116f4d1d..b6f8755b13 100644 --- a/plugins/DevicePlugins/Reports/Base.php +++ b/plugins/DevicePlugins/Reports/Base.php @@ -15,7 +15,7 @@ abstract class Base extends \Piwik\Plugin\Report { protected function init() { - $this->category = 'General_VisitorSettings'; + $this->categoryId = 'General_Visitors'; } protected function getBasicDevicePluginsDisplayProperties(ViewDataTable $view) diff --git a/plugins/DevicePlugins/Reports/GetPlugin.php b/plugins/DevicePlugins/Reports/GetPlugin.php index 151bf3e1a6..42fef1cb89 100644 --- a/plugins/DevicePlugins/Reports/GetPlugin.php +++ b/plugins/DevicePlugins/Reports/GetPlugin.php @@ -23,8 +23,9 @@ class GetPlugin extends Base $this->metrics = array('nb_visits'); $this->constantRowsCount = true; $this->processedMetrics = array('nb_visits_percentage'); - $this->order = 4; - $this->widgetTitle = 'DevicePlugins_WidgetPlugins'; + $this->order = 13; + + $this->subcategoryId = 'DevicesDetection_Software'; } public function configureView(ViewDataTable $view) diff --git a/plugins/DevicesDetection/Controller.php b/plugins/DevicesDetection/Controller.php index 10c55a8a96..d19d0cf403 100644 --- a/plugins/DevicesDetection/Controller.php +++ b/plugins/DevicesDetection/Controller.php @@ -13,52 +13,11 @@ use Piwik\Common; use Piwik\Db; use Piwik\Piwik; use Piwik\Plugin\ControllerAdmin; -use Piwik\Plugin\Manager AS PluginManager; use Piwik\Plugin\Report; use Piwik\View; class Controller extends \Piwik\Plugin\Controller { - public function index() - { - return $this->devices(); - } - - public function devices() - { - $view = new View('@DevicesDetection/devices'); - $view->deviceTypes = $this->renderReport('getType'); - $view->deviceBrands = $this->renderReport('getBrand'); - $view->deviceModels = $this->renderReport('getModel'); - - $isResolutionEnabled = PluginManager::getInstance()->isPluginActivated('Resolution'); - if ($isResolutionEnabled) { - $view->resolutions = $this->renderReport(Report::factory('Resolution', 'getResolution')); - } - - return $view->render(); - } - - public function software() - { - $view = new View('@DevicesDetection/software'); - $view->osReport = $this->renderReport('getOsVersions'); - $view->browserReport = $this->renderReport('getBrowsers'); - $view->browserEngineReport = $this->renderReport('getBrowserEngines'); - - $isResolutionEnabled = PluginManager::getInstance()->isPluginActivated('Resolution'); - if ($isResolutionEnabled) { - $view->configurations = $this->renderReport(Report::factory('Resolution', 'getConfiguration')); - } - - $isDevicePluginsEnabled = PluginManager::getInstance()->isPluginActivated('DevicePlugins'); - if ($isDevicePluginsEnabled) { - $view->browserPlugins = $this->renderReport(Report::factory('DevicePlugins', 'getPlugin')); - } - - return $view->render(); - } - public function detection() { Piwik::checkUserHasSomeAdminAccess(); diff --git a/plugins/DevicesDetection/Menu.php b/plugins/DevicesDetection/Menu.php index 7ddb1dc668..067f8b9afa 100644 --- a/plugins/DevicesDetection/Menu.php +++ b/plugins/DevicesDetection/Menu.php @@ -9,7 +9,6 @@ namespace Piwik\Plugins\DevicesDetection; use Piwik\Menu\MenuAdmin; -use Piwik\Menu\MenuReporting; use Piwik\Piwik; /** @@ -24,10 +23,4 @@ class Menu extends \Piwik\Plugin\Menu $order = 40); } } - - public function configureReportingMenu(MenuReporting $menu) - { - $menu->addVisitorsItem('DevicesDetection_Devices', $this->urlForAction('devices')); - $menu->addVisitorsItem('DevicesDetection_Software', $this->urlForAction('software')); - } } diff --git a/plugins/DevicesDetection/Reports/Base.php b/plugins/DevicesDetection/Reports/Base.php index 15eac96a4a..cb24a376e4 100644 --- a/plugins/DevicesDetection/Reports/Base.php +++ b/plugins/DevicesDetection/Reports/Base.php @@ -14,6 +14,6 @@ abstract class Base extends \Piwik\Plugin\Report { protected function init() { - $this->category = 'DevicesDetection_DevicesDetection'; + $this->categoryId = 'General_Visitors'; } } diff --git a/plugins/DevicesDetection/Reports/GetBrand.php b/plugins/DevicesDetection/Reports/GetBrand.php index 070b2d8918..41b9fd5366 100644 --- a/plugins/DevicesDetection/Reports/GetBrand.php +++ b/plugins/DevicesDetection/Reports/GetBrand.php @@ -20,8 +20,9 @@ class GetBrand extends Base $this->dimension = new DeviceBrand(); $this->name = Piwik::translate('DevicesDetection_DeviceBrand'); $this->documentation = ''; // TODO - $this->order = 1; - $this->widgetTitle = 'DevicesDetection_DeviceBrand'; + $this->order = 4; + + $this->subcategoryId = 'DevicesDetection_Devices'; } public function configureView(ViewDataTable $view) diff --git a/plugins/DevicesDetection/Reports/GetBrowserEngines.php b/plugins/DevicesDetection/Reports/GetBrowserEngines.php index 7c47ffca63..403955c66c 100644 --- a/plugins/DevicesDetection/Reports/GetBrowserEngines.php +++ b/plugins/DevicesDetection/Reports/GetBrowserEngines.php @@ -21,8 +21,9 @@ class GetBrowserEngines extends Base $this->dimension = new BrowserEngine(); $this->name = Piwik::translate('DevicesDetection_BrowserEngines'); $this->documentation = Piwik::translate('DevicesDetection_BrowserEngineDocumentation', '
    '); - $this->order = 7; - $this->widgetTitle = 'DevicesDetection_BrowserEngines'; + $this->order = 10; + + $this->subcategoryId = 'DevicesDetection_Software'; } public function getDefaultTypeViewDataTable() diff --git a/plugins/DevicesDetection/Reports/GetBrowserVersions.php b/plugins/DevicesDetection/Reports/GetBrowserVersions.php index 4f5875199a..66c7f91f55 100644 --- a/plugins/DevicesDetection/Reports/GetBrowserVersions.php +++ b/plugins/DevicesDetection/Reports/GetBrowserVersions.php @@ -11,6 +11,7 @@ namespace Piwik\Plugins\DevicesDetection\Reports; use Piwik\Piwik; use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\DevicesDetection\Columns\BrowserVersion; +use Piwik\Plugin\Reports; class GetBrowserVersions extends Base { @@ -20,8 +21,9 @@ class GetBrowserVersions extends Base $this->dimension = new BrowserVersion(); $this->name = Piwik::translate('DevicesDetection_BrowserVersion'); $this->documentation = ''; // TODO - $this->order = 2; - $this->widgetTitle = 'DevicesDetection_BrowserVersion'; + $this->order = 6; + + $this->subcategoryId = 'DevicesDetection_Software'; } public function configureView(ViewDataTable $view) @@ -34,7 +36,7 @@ class GetBrowserVersions extends Base public function getRelatedReports() { return array( - self::factory('DevicesDetection', 'getBrowsers'), + Reports::factory('DevicesDetection', 'getBrowsers'), ); } } diff --git a/plugins/DevicesDetection/Reports/GetBrowsers.php b/plugins/DevicesDetection/Reports/GetBrowsers.php index 7d08a51ce5..5c39a275ee 100644 --- a/plugins/DevicesDetection/Reports/GetBrowsers.php +++ b/plugins/DevicesDetection/Reports/GetBrowsers.php @@ -11,6 +11,7 @@ namespace Piwik\Plugins\DevicesDetection\Reports; use Piwik\Piwik; use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\DevicesDetection\Columns\BrowserName; +use Piwik\Plugin\Reports; class GetBrowsers extends Base { @@ -18,10 +19,11 @@ class GetBrowsers extends Base { parent::init(); $this->dimension = new BrowserName(); - $this->name = Piwik::translate('DevicesDetection_WidgetBrowsers'); + $this->name = Piwik::translate('DevicesDetection_Browsers'); $this->documentation = Piwik::translate('DevicesDetection_WidgetBrowsersDocumentation', '
    '); - $this->order = 1; - $this->widgetTitle = 'DevicesDetection_WidgetBrowsers'; + $this->order = 5; + + $this->subcategoryId = 'DevicesDetection_Software'; } public function configureView(ViewDataTable $view) @@ -35,7 +37,7 @@ class GetBrowsers extends Base public function getRelatedReports() { return array( - self::factory('DevicesDetection', 'getBrowserVersions'), + Reports::factory('DevicesDetection', 'getBrowserVersions'), ); } } diff --git a/plugins/DevicesDetection/Reports/GetModel.php b/plugins/DevicesDetection/Reports/GetModel.php index e2241e1ad4..154464691c 100644 --- a/plugins/DevicesDetection/Reports/GetModel.php +++ b/plugins/DevicesDetection/Reports/GetModel.php @@ -21,7 +21,8 @@ class GetModel extends Base $this->name = Piwik::translate('DevicesDetection_DeviceModel'); $this->documentation = ''; // TODO $this->order = 2; - $this->widgetTitle = 'DevicesDetection_DeviceModel'; + + $this->subcategoryId = 'DevicesDetection_Devices'; } public function configureView(ViewDataTable $view) diff --git a/plugins/DevicesDetection/Reports/GetOsFamilies.php b/plugins/DevicesDetection/Reports/GetOsFamilies.php index 61b393cb44..a283a83f7b 100644 --- a/plugins/DevicesDetection/Reports/GetOsFamilies.php +++ b/plugins/DevicesDetection/Reports/GetOsFamilies.php @@ -11,6 +11,7 @@ namespace Piwik\Plugins\DevicesDetection\Reports; use Piwik\Piwik; use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\DevicesDetection\Columns\Os; +use Piwik\Plugin\Reports; class GetOsFamilies extends Base { @@ -20,8 +21,9 @@ class GetOsFamilies extends Base $this->dimension = new Os(); $this->name = Piwik::translate('DevicesDetection_OperatingSystemFamilies'); $this->documentation = ''; // TODO - $this->order = 3; - $this->widgetTitle = 'DevicesDetection_OperatingSystemFamilies'; + $this->order = 8; + + $this->subcategoryId = 'DevicesDetection_Software'; } public function configureView(ViewDataTable $view) @@ -35,7 +37,7 @@ class GetOsFamilies extends Base public function getRelatedReports() { return array( - self::factory('DevicesDetection', 'getOsVersions'), + Reports::factory('DevicesDetection', 'getOsVersions'), ); } diff --git a/plugins/DevicesDetection/Reports/GetOsVersions.php b/plugins/DevicesDetection/Reports/GetOsVersions.php index 8676f38776..b330054c6f 100644 --- a/plugins/DevicesDetection/Reports/GetOsVersions.php +++ b/plugins/DevicesDetection/Reports/GetOsVersions.php @@ -11,6 +11,7 @@ namespace Piwik\Plugins\DevicesDetection\Reports; use Piwik\Piwik; use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\DevicesDetection\Columns\OsVersion; +use Piwik\Plugin\Reports; class GetOsVersions extends Base { @@ -20,8 +21,9 @@ class GetOsVersions extends Base $this->dimension = new OsVersion(); $this->name = Piwik::translate('DevicesDetection_OperatingSystemVersions'); $this->documentation = ''; // TODO - $this->order = 4; - $this->widgetTitle = 'DevicesDetection_OperatingSystemVersions'; + $this->order = 2; + + $this->subcategoryId = 'DevicesDetection_Software'; } public function configureView(ViewDataTable $view) @@ -35,7 +37,7 @@ class GetOsVersions extends Base public function getRelatedReports() { return array( - self::factory('DevicesDetection', 'getOsFamilies'), + Reports::factory('DevicesDetection', 'getOsFamilies'), ); } } diff --git a/plugins/DevicesDetection/Reports/GetType.php b/plugins/DevicesDetection/Reports/GetType.php index cbfa69db3d..b12f19f319 100644 --- a/plugins/DevicesDetection/Reports/GetType.php +++ b/plugins/DevicesDetection/Reports/GetType.php @@ -22,7 +22,8 @@ class GetType extends Base $this->name = Piwik::translate('DevicesDetection_DeviceType'); $this->documentation = ''; // TODO $this->order = 0; - $this->widgetTitle = 'DevicesDetection_DeviceType'; + + $this->subcategoryId = 'DevicesDetection_Devices'; } public function configureView(ViewDataTable $view) diff --git a/plugins/DevicesDetection/templates/devices.twig b/plugins/DevicesDetection/templates/devices.twig deleted file mode 100644 index a37079c9fd..0000000000 --- a/plugins/DevicesDetection/templates/devices.twig +++ /dev/null @@ -1,19 +0,0 @@ -
    - -
    -

    {{ "DevicesDetection_DeviceType"|translate }}

    - {{ deviceTypes | raw}} -

    {{ "DevicesDetection_DeviceBrand"|translate }}

    - {{ deviceBrands | raw }} -
    - -
    -

    {{ "DevicesDetection_DeviceModel"|translate }}

    - {{ deviceModels | raw }} - {% if resolutions|default is not empty %} -

    {{ 'Resolution_Resolutions'|translate }}

    - {{ resolutions|raw }} - {% endif %} -
    - -
    diff --git a/plugins/DevicesDetection/templates/software.twig b/plugins/DevicesDetection/templates/software.twig deleted file mode 100644 index 8b0dab0631..0000000000 --- a/plugins/DevicesDetection/templates/software.twig +++ /dev/null @@ -1,23 +0,0 @@ -
    - -
    -

    {{ "DevicesDetection_OperatingSystems"|translate }}

    - {{ osReport | raw}} - {% if configurations|default is not empty %} -

    {{ 'Resolution_Configurations'|translate }}

    - {{ configurations|raw }} - {% endif %} -
    - -
    -

    {{ "DevicesDetection_Browsers"|translate }}

    - {{ browserReport | raw }} -

    {{ "DevicesDetection_BrowserEngines"|translate }}

    - {{ browserEngineReport | raw }} - {% if browserPlugins|default is not empty %} -

    {{ 'General_Plugins'|translate }}

    - {{ browserPlugins|raw }} - {% endif %} -
    - -
    diff --git a/plugins/Ecommerce/Categories/EcommerceCategory.php b/plugins/Ecommerce/Categories/EcommerceCategory.php new file mode 100644 index 0000000000..39cd5bb3ea --- /dev/null +++ b/plugins/Ecommerce/Categories/EcommerceCategory.php @@ -0,0 +1,17 @@ +isPluginActivated('CustomVariables')) { - throw new Exception("Ecommerce Tracking requires that the plugin Custom Variables is enabled. Please enable the plugin CustomVariables (or ask your admin)."); - } + $idGoal = Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER; - $view = $this->getGoalReportView($idGoal = Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER); - $view->displayFullReport = false; - $view->headline = $this->translator->translate('General_EvolutionOverPeriod'); + $view = new View('@Ecommerce/getSparklines'); + $view->onlyConversionOverview = false; + $view->conversionsOverViewEnabled = true; - return $view->render(); - } + if ($idGoal == Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER) { + $goalDefinition['name'] = $this->translator->translate('Goals_Ecommerce'); + $goalDefinition['allow_multiple'] = true; + } else { + if (!isset($this->goals[$idGoal])) { + Piwik::redirectToModule('Goals', 'index', array('idGoal' => null)); + } + $goalDefinition = $this->goals[$idGoal]; + } - public function ecommerceLogReport($fetch = false) - { - $view = new View('@Ecommerce/ecommerceLog'); $this->setGeneralVariablesView($view); - $view->ecommerceLog = $this->getEcommerceLog($fetch); - - return $view->render(); - } + $goal = $this->getMetricsForGoal($idGoal); + foreach ($goal as $name => $value) { + $view->$name = $value; + } - public function getEcommerceLog($fetch = false) - { - $saveGET = $_GET; - $_GET['segment'] = urlencode('visitEcommerceStatus!=none'); - $_GET['widget'] = 1; - $output = FrontController::getInstance()->dispatch('Live', 'getVisitorLog', array($fetch)); - $_GET = $saveGET; + if ($idGoal == Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER) { + $goal = $this->getMetricsForGoal(Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_CART); + foreach ($goal as $name => $value) { + $name = 'cart_' . $name; + $view->$name = $value; + } + } - return $output; - } + $view->idGoal = $idGoal; + $view->goalAllowMultipleConversionsPerVisit = $goalDefinition['allow_multiple']; - public function index() - { - return $this->ecommerceReport(); + return $view->render(); } - public function products() + public function getConversionsOverview() { - $goal = $this->getMetricsForGoal(Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER); - $conversions = 0; - if (!empty($goal['nb_conversions'])) { - $conversions = $goal['nb_conversions']; - } - - $goal = $this->getMetricsForGoal(Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_CART); - - $cartNbConversions = 0; - if (!empty($goal) && array_key_exists('nb_conversions', $goal)) { - $cartNbConversions = $goal['nb_conversions']; - } + $view = new View('@Ecommerce/conversionOverview'); + $idGoal = Common::getRequestVar('idGoal', null, 'string'); - $preloadAbandonedCart = $cartNbConversions !== false && $conversions == 0; + $goalMetrics = Request::processRequest('Goals.get', array('idGoal' => $idGoal)); + $dataRow = $goalMetrics->getFirstRow(); - $goalReportsByDimension = new View\ReportsByDimension('Goals'); + $view->idSite = Common::getRequestVar('idSite', null, 'int'); - $ecommerceCustomParams = array(); - if ($preloadAbandonedCart) { - $ecommerceCustomParams['abandonedCarts'] = '1'; - } else { - $ecommerceCustomParams['abandonedCarts'] = '0'; + if ($dataRow) { + $view->revenue = $dataRow->getColumn('revenue'); + $view->revenue_subtotal = $dataRow->getColumn('revenue_subtotal'); + $view->revenue_tax = $dataRow->getColumn('revenue_tax'); + $view->revenue_shipping = $dataRow->getColumn('revenue_shipping'); + $view->revenue_discount = $dataRow->getColumn('revenue_discount'); } - $goalReportsByDimension->addReport( - 'Goals_Products', 'Goals_ProductSKU', 'Goals.getItemsSku', $ecommerceCustomParams); - $goalReportsByDimension->addReport( - 'Goals_Products', 'Goals_ProductName', 'Goals.getItemsName', $ecommerceCustomParams); - $goalReportsByDimension->addReport( - 'Goals_Products', 'Goals_ProductCategory', 'Goals.getItemsCategory', $ecommerceCustomParams); - - $view = new View('@Ecommerce/products'); - $this->setGeneralVariablesView($view); - - $view->productsByDimension = $goalReportsByDimension->render(); return $view->render(); } - public function sales() + public function getEcommerceLog($fetch = false) { - $viewOverview = $this->getGoalReportView(Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER); - $reportsByDimension = $viewOverview->goalReportsByDimension; - - $view = new View('@Ecommerce/sales'); - $this->setGeneralVariablesView($view); + $saveGET = $_GET; + $_GET['segment'] = urlencode('visitEcommerceStatus!=none'); + $_GET['widget'] = 1; + $output = FrontController::getInstance()->dispatch('Live', 'getVisitorLog', array($fetch)); + $_GET = $saveGET; - $view->goalReportsByDimension = $reportsByDimension; - return $view->render(); + return $output; } } diff --git a/plugins/Ecommerce/Menu.php b/plugins/Ecommerce/Menu.php deleted file mode 100644 index 331715be4f..0000000000 --- a/plugins/Ecommerce/Menu.php +++ /dev/null @@ -1,41 +0,0 @@ -isEcommerceEnabled()) { - $ecommerceParams = array('idGoal' => Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER); - $ecommerceUrl = $this->urlForAction('ecommerceReport', $ecommerceParams); - - $menu->addItem('Goals_Ecommerce', '', $ecommerceUrl, 24); - $menu->addItem('Goals_Ecommerce', 'General_Overview', $ecommerceUrl, 1); - $menu->addItem('Goals_Ecommerce', 'Goals_EcommerceLog', $this->urlForAction('ecommerceLogReport'), 2); - $menu->addItem('Goals_Ecommerce', 'Goals_Products', $this->urlForAction('products', $ecommerceParams), 3); - $menu->addItem('Goals_Ecommerce', 'Ecommerce_Sales', $this->urlForAction('sales', $ecommerceParams), 4); - } - - } -} diff --git a/plugins/Ecommerce/Reports/Base.php b/plugins/Ecommerce/Reports/Base.php index 08a766792a..28a3a4a36f 100644 --- a/plugins/Ecommerce/Reports/Base.php +++ b/plugins/Ecommerce/Reports/Base.php @@ -8,20 +8,17 @@ */ namespace Piwik\Plugins\Ecommerce\Reports; -use Piwik\API\Proxy; use Piwik\Common; use Piwik\Piwik; use Piwik\Plugin\Report; use Piwik\Site; -use Piwik\ViewDataTable\Factory as ViewDataTableFactory; -use Piwik\WidgetsList; abstract class Base extends Report { protected function init() { $this->module = 'Goals'; - $this->category = 'Goals_Ecommerce'; + $this->categoryId = 'Goals_Ecommerce'; } public function isEnabled() diff --git a/plugins/Ecommerce/Reports/BaseItem.php b/plugins/Ecommerce/Reports/BaseItem.php index 5caf770a6b..5896710dc2 100644 --- a/plugins/Ecommerce/Reports/BaseItem.php +++ b/plugins/Ecommerce/Reports/BaseItem.php @@ -9,15 +9,18 @@ namespace Piwik\Plugins\Ecommerce\Reports; use Piwik\Common; +use Piwik\DataTable; use Piwik\Metrics\Formatter; use Piwik\Piwik; -use Piwik\Plugin\Report; use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Evolution; -use Piwik\Plugins\Goals\Goals; use Piwik\Plugins\Goals\Columns\Metrics\AveragePrice; use Piwik\Plugins\Goals\Columns\Metrics\AverageQuantity; use Piwik\Plugins\Goals\Columns\Metrics\ProductConversionRate; +use Piwik\Plugins\Goals\Conversions; +use Piwik\Plugins\Goals\Model; +use Piwik\Report\ReportWidgetFactory; +use Piwik\Widget\WidgetsList; abstract class BaseItem extends Base { @@ -46,7 +49,8 @@ abstract class BaseItem extends Base public function getMetricsDocumentation() { - if ($this->isAbandonedCart()) { + // we do not check whether it is abondon carts if not set re performance improvements + if ($this->isAbandonedCart($fetchIfNotSet = false)) { return array( 'revenue' => Piwik::translate('Goals_ColumnRevenueDocumentation', Piwik::translate('Goals_DocumentationRevenueGeneratedByProductSales')), @@ -62,6 +66,11 @@ abstract class BaseItem extends Base return array(); } + public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory) + { + $widgetsList->addToContainerWidget('Products', $factory->createWidget()); + } + public function configureView(ViewDataTable $view) { $idSite = Common::getRequestVar('idSite'); @@ -100,7 +109,7 @@ abstract class BaseItem extends Base $view->config->custom_parameters['viewDataTable'] = 'table'; $abandonedCart = true; } else { - $abandonedCart = $this->isAbandonedCart(); + $abandonedCart = $this->isAbandonedCart($fetchIfNotSet = true); } if ($abandonedCart) { @@ -127,8 +136,32 @@ abstract class BaseItem extends Base $view->config->columns_to_display = $columnsOrdered; } - private function isAbandonedCart() + private function isAbandonedCart($fetchIfNotSet) { - return Common::getRequestVar('abandonedCarts', '0', 'string') == 1; + $abandonedCarts = Common::getRequestVar('abandonedCarts', '', 'string'); + + if ($abandonedCarts === '') { + if ($fetchIfNotSet) { + + $idSite = Common::getRequestVar('idSite', 0, 'int'); + $period = Common::getRequestVar('period', '', 'string'); + $date = Common::getRequestVar('date', '', 'string'); + + $conversion = new Conversions(); + $conversions = $conversion->getConversionForGoal(Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER, $idSite, $period, $date); + $cartNbConversions = $conversion->getConversionForGoal(Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_CART, $idSite, $period, $date); + $preloadAbandonedCart = $cartNbConversions !== false && $conversions == 0; + + if ($preloadAbandonedCart) { + $abandonedCarts = '1'; + } else { + $abandonedCarts = '0'; + } + } else { + $abandonedCarts = '0'; + } + } + + return $abandonedCarts == '1'; } } diff --git a/plugins/Ecommerce/Reports/GetItemsCategory.php b/plugins/Ecommerce/Reports/GetItemsCategory.php index bf652ca10d..efd4a9489a 100644 --- a/plugins/Ecommerce/Reports/GetItemsCategory.php +++ b/plugins/Ecommerce/Reports/GetItemsCategory.php @@ -20,6 +20,7 @@ class GetItemsCategory extends BaseItem $this->name = Piwik::translate('Goals_ProductCategory'); $this->dimension = new ProductCategory(); $this->order = 32; - $this->widgetTitle = 'Goals_ProductCategory'; + + $this->subcategoryId = 'Goals_Products'; } } diff --git a/plugins/Ecommerce/Reports/GetItemsName.php b/plugins/Ecommerce/Reports/GetItemsName.php index a320b760e4..db8c7f5d3d 100644 --- a/plugins/Ecommerce/Reports/GetItemsName.php +++ b/plugins/Ecommerce/Reports/GetItemsName.php @@ -20,6 +20,7 @@ class GetItemsName extends BaseItem $this->name = Piwik::translate('Goals_ProductName'); $this->dimension = new ProductName(); $this->order = 31; - $this->widgetTitle = 'Goals_ProductName'; + + $this->subcategoryId = 'Goals_Products'; } } diff --git a/plugins/Ecommerce/Reports/GetItemsSku.php b/plugins/Ecommerce/Reports/GetItemsSku.php index a2b20eb3f9..9056b2ff6c 100644 --- a/plugins/Ecommerce/Reports/GetItemsSku.php +++ b/plugins/Ecommerce/Reports/GetItemsSku.php @@ -21,7 +21,8 @@ class GetItemsSku extends BaseItem $this->name = Piwik::translate('Goals_ProductSKU'); $this->dimension = new ProductSku(); $this->order = 30; - $this->widgetTitle = 'Goals_ProductSKU'; + + $this->subcategoryId = 'Goals_Products'; } } diff --git a/plugins/Ecommerce/Widgets.php b/plugins/Ecommerce/Widgets.php deleted file mode 100644 index e20a73850e..0000000000 --- a/plugins/Ecommerce/Widgets.php +++ /dev/null @@ -1,35 +0,0 @@ -getIdSite(); - - $site = new Site($idSite); - if ($site->isEcommerceEnabled()) { - $this->addWidget('General_Overview', 'widgetGoalReport', array('idGoal' => Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER)); - $this->addWidget('Goals_EcommerceLog', 'getEcommerceLog'); - } - } - - private function getIdSite() - { - return Common::getRequestVar('idSite', null, 'int'); - } - -} diff --git a/plugins/Ecommerce/Widgets/GetEcommerceLog.php b/plugins/Ecommerce/Widgets/GetEcommerceLog.php new file mode 100644 index 0000000000..d1a68a435a --- /dev/null +++ b/plugins/Ecommerce/Widgets/GetEcommerceLog.php @@ -0,0 +1,28 @@ +setCategoryId('Goals_Ecommerce'); + $config->setSubcategoryId('Goals_EcommerceLog'); + $config->setName('Goals_EcommerceLog'); + + $idSite = Common::getRequestVar('idSite', null, 'int'); + $site = new Site($idSite); + $config->setIsEnabled($site->isEcommerceEnabled()); + } + +} diff --git a/plugins/Ecommerce/Widgets/ProductsByDimension.php b/plugins/Ecommerce/Widgets/ProductsByDimension.php new file mode 100644 index 0000000000..2f25e23b76 --- /dev/null +++ b/plugins/Ecommerce/Widgets/ProductsByDimension.php @@ -0,0 +1,34 @@ +isEcommerceEnabled(); + } +} diff --git a/plugins/Ecommerce/templates/conversionOverview.twig b/plugins/Ecommerce/templates/conversionOverview.twig new file mode 100644 index 0000000000..9b6864c03c --- /dev/null +++ b/plugins/Ecommerce/templates/conversionOverview.twig @@ -0,0 +1,15 @@ +
      + {{ 'General_ColumnRevenue'|translate }}: {{ revenue|money(idSite)|raw -}} + {% if revenue_subtotal is not empty %}, + {{ 'General_Subtotal'|translate }}: {{ revenue_subtotal|money(idSite)|raw -}} + {% endif %} + {%- if revenue_tax is not empty -%}, + {{ 'General_Tax'|translate }}: {{ revenue_tax|money(idSite)|raw -}} + {% endif %} + {%- if revenue_shipping is not empty -%}, + {{ 'General_Shipping'|translate }}: {{ revenue_shipping|money(idSite)|raw -}} + {% endif %} + {%- if revenue_discount is not empty -%}, + {{ 'General_Discount'|translate }}: {{ revenue_discount|money(idSite)|raw -}} + {% endif %} +

    \ No newline at end of file diff --git a/plugins/Ecommerce/templates/ecommerceLog.twig b/plugins/Ecommerce/templates/ecommerceLog.twig deleted file mode 100644 index 4c40a94d99..0000000000 --- a/plugins/Ecommerce/templates/ecommerceLog.twig +++ /dev/null @@ -1,3 +0,0 @@ -

    {{ 'Goals_EcommerceLog'|translate }}

    - -{{ ecommerceLog|raw }} diff --git a/plugins/Ecommerce/templates/getSparklines.twig b/plugins/Ecommerce/templates/getSparklines.twig new file mode 100644 index 0000000000..0952c081a5 --- /dev/null +++ b/plugins/Ecommerce/templates/getSparklines.twig @@ -0,0 +1,55 @@ +
    +
    {{ sparkline(urlSparklineConversions) }} + {{ nb_conversions }} + {{ 'General_EcommerceOrders'|translate }} + + + {% if goalAllowMultipleConversionsPerVisit is defined and goalAllowMultipleConversionsPerVisit %} + ({{ 'General_NVisits'|translate(""~nb_visits_converted~"")|raw }}) + {% endif %} +
    + +
    + {{ sparkline(urlSparklineRevenue) }} + {% set revenue=revenue|money(idSite) %} + {{ revenue|raw }} {{ 'General_TotalRevenue'|translate }} +
    + +
    {{ sparkline(urlSparklineAverageOrderValue) }} + {{ avg_order_revenue|money(idSite)|raw }} + {{ 'General_AverageOrderValue'|translate }} +
    +
    +
    +
    {{ sparkline(urlSparklineConversionRate) }} + {% set ecommerceOrdersText %}{{ 'General_EcommerceOrders'|translate }}{% endset %} + {{ 'Goals_ConversionRate'|translate(""~conversion_rate~" "~ecommerceOrdersText)|raw }} +
    +
    {{ sparkline(urlSparklinePurchasedProducts) }} + {{ items }} {{ 'General_PurchasedProducts'|translate }}
    +
    +
    +
    + {{ 'General_AbandonedCarts'|translate }} +
    + +
    + {{ sparkline(cart_urlSparklineConversions) }} + {% set ecommerceAbandonedCartsText %}{{ 'Goals_AbandonedCart'|translate }}{% endset %} + {{ cart_nb_conversions }} {{ 'General_VisitsWith'|translate(ecommerceAbandonedCartsText) }} +
    + +
    + {{ sparkline(cart_urlSparklineRevenue) }} + {% set revenue %}{{ cart_revenue|money(idSite)|raw }}{% endset %} + {% set revenueText %}{{ 'General_ColumnRevenue'|translate }}{% endset %} + {{ revenue }} {{ 'Goals_LeftInCart'|translate(revenueText) }} +
    + +
    + {{ sparkline(cart_urlSparklineConversionRate) }} + {{ cart_conversion_rate }} + {{ 'General_VisitsWith'|translate(ecommerceAbandonedCartsText) }} +
    +
    +{% include "_sparklineFooter.twig" %} diff --git a/plugins/Events/Categories/EventsSubcategory.php b/plugins/Events/Categories/EventsSubcategory.php new file mode 100644 index 0000000000..e969029e13 --- /dev/null +++ b/plugins/Events/Categories/EventsSubcategory.php @@ -0,0 +1,19 @@ +leftMenuReports = $this->getLeftMenuReports(); - return $view->render(); - } - - private function getLeftMenuReports() - { - $reports = new View\ReportsByDimension('Events'); - foreach(Events::getLabelTranslations() as $apiAction => $translations) { - // 'getCategory' is the API method, but we are loading 'indexCategory' which displays

    - $count = 1; - $controllerAction = str_replace("get", "index", $apiAction, $count); - $params = array( - 'secondaryDimension' => API::getInstance()->getDefaultSecondaryDimension($apiAction) - ); - $reports->addReport('Events_TopEvents', $translations[0], 'Events.' . $controllerAction, $params); - } - return $reports->render(); - } - - public function indexCategory() - { - return $this->indexEvent(__FUNCTION__); - } - - public function indexAction() - { - return $this->indexEvent(__FUNCTION__); - } - - public function indexName() - { - return $this->indexEvent(__FUNCTION__); - } - - public function getActionFromCategoryId() - { - return $this->renderReport(__FUNCTION__); - } - - public function getNameFromCategoryId() - { - return $this->renderReport(__FUNCTION__); - } - - public function getCategoryFromActionId() - { - return $this->renderReport(__FUNCTION__); - } - - public function getNameFromActionId() - { - return $this->renderReport(__FUNCTION__); - } - - public function getActionFromNameId() - { - return $this->renderReport(__FUNCTION__); - } - - public function getCategoryFromNameId() - { - return $this->renderReport(__FUNCTION__); - } - - protected function indexEvent($controllerMethod) - { - $count = 1; - $apiMethod = str_replace('index', 'get', $controllerMethod, $count); - $events = new Events; - $title = $events->getReportTitleTranslation($apiMethod); - - if (method_exists($this, $apiMethod)) { - $content = $this->$apiMethod(); - } else { - $content = $this->renderReport($apiMethod); - } - - return View::singleReport( - $title, - $content - ); - } -} diff --git a/plugins/Events/Events.php b/plugins/Events/Events.php index ba3e96465d..f09e1a9925 100644 --- a/plugins/Events/Events.php +++ b/plugins/Events/Events.php @@ -12,6 +12,7 @@ use Piwik\Common; use Piwik\Piwik; use Piwik\Plugin\Report; use Piwik\Plugin\ViewDataTable; +use Piwik\Plugin\Reports; class Events extends \Piwik\Plugin { @@ -154,7 +155,7 @@ class Events extends \Piwik\Plugin $this->addRelatedReports($view, $secondaryDimension); $this->addTooltipEventValue($view); - $subtableReport = Report::factory('Events', $view->config->subtable_controller_action); + $subtableReport = Reports::factory('Events', $view->config->subtable_controller_action); $view->config->pivot_by_dimension = $subtableReport->getDimension()->getId(); $view->config->pivot_by_column = 'nb_events'; } diff --git a/plugins/Events/Menu.php b/plugins/Events/Menu.php deleted file mode 100644 index 440a35978e..0000000000 --- a/plugins/Events/Menu.php +++ /dev/null @@ -1,21 +0,0 @@ -addActionsItem('Events_Events', $this->urlForAction('index'), 30); - } -} diff --git a/plugins/Events/Reports/Base.php b/plugins/Events/Reports/Base.php index 4430b31407..a43ba0dbfa 100644 --- a/plugins/Events/Reports/Base.php +++ b/plugins/Events/Reports/Base.php @@ -10,19 +10,31 @@ namespace Piwik\Plugins\Events\Reports; use Piwik\Plugins\Events\API; use Piwik\Plugins\Events\Columns\Metrics\AverageEventValue; +use Piwik\Report\ReportWidgetFactory; +use Piwik\Widget\WidgetsList; abstract class Base extends \Piwik\Plugin\Report { protected function init() { - $this->category = 'Events_Events'; + $this->categoryId = 'General_Actions'; + $this->subcategoryId = 'Events_Events'; + $this->processedMetrics = array( new AverageEventValue() ); + } - $this->widgetParams = array( - 'secondaryDimension' => API::getInstance()->getDefaultSecondaryDimension($this->action) - ); + public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory) + { + if (!$this->isSubtableReport) { + $widget = $factory->createWidget()->setParameters(array( + 'secondaryDimension' => API::getInstance()->getDefaultSecondaryDimension($this->action) + )); + + $widgetsList->addToContainerWidget('Events', $widget); + } } + } diff --git a/plugins/Events/Reports/GetAction.php b/plugins/Events/Reports/GetAction.php index 84f750e264..bbdadd7ed4 100644 --- a/plugins/Events/Reports/GetAction.php +++ b/plugins/Events/Reports/GetAction.php @@ -27,6 +27,5 @@ class GetAction extends Base $this->actionToLoadSubTables = 'getNameFromActionId'; } $this->order = 1; - $this->widgetTitle = 'Events_EventActions'; } } diff --git a/plugins/Events/Reports/GetActionFromCategoryId.php b/plugins/Events/Reports/GetActionFromCategoryId.php index e5de6af9ca..9c355d4de1 100644 --- a/plugins/Events/Reports/GetActionFromCategoryId.php +++ b/plugins/Events/Reports/GetActionFromCategoryId.php @@ -19,7 +19,7 @@ class GetActionFromCategoryId extends Report { protected function init() { - $this->category = 'Events_Events'; + $this->categoryId = 'Events_Events'; $this->processedMetrics = false; $this->dimension = new EventAction(); $this->name = Piwik::translate('Events_EventActions'); diff --git a/plugins/Events/Reports/GetActionFromNameId.php b/plugins/Events/Reports/GetActionFromNameId.php index 55bd628459..1da175e47b 100644 --- a/plugins/Events/Reports/GetActionFromNameId.php +++ b/plugins/Events/Reports/GetActionFromNameId.php @@ -19,7 +19,7 @@ class GetActionFromNameId extends Report { protected function init() { - $this->category = 'Events_Events'; + $this->categoryId = 'Events_Events'; $this->processedMetrics = false; $this->dimension = new EventAction(); $this->name = Piwik::translate('Events_EventActions'); diff --git a/plugins/Events/Reports/GetCategory.php b/plugins/Events/Reports/GetCategory.php index be867705ea..2049868e7c 100644 --- a/plugins/Events/Reports/GetCategory.php +++ b/plugins/Events/Reports/GetCategory.php @@ -27,6 +27,5 @@ class GetCategory extends Base $this->actionToLoadSubTables = 'getActionFromCategoryId'; } $this->order = 0; - $this->widgetTitle = 'Events_EventCategories'; } } diff --git a/plugins/Events/Reports/GetCategoryFromActionId.php b/plugins/Events/Reports/GetCategoryFromActionId.php index 51f5f6918d..47e62c9260 100644 --- a/plugins/Events/Reports/GetCategoryFromActionId.php +++ b/plugins/Events/Reports/GetCategoryFromActionId.php @@ -19,7 +19,7 @@ class GetCategoryFromActionId extends Report { protected function init() { - $this->category = 'Events_Events'; + $this->categoryId = 'Events_Events'; $this->processedMetrics = false; $this->dimension = new EventCategory(); $this->name = Piwik::translate('Events_EventCategories'); diff --git a/plugins/Events/Reports/GetCategoryFromNameId.php b/plugins/Events/Reports/GetCategoryFromNameId.php index 4806c97d0f..0eef6b5f32 100644 --- a/plugins/Events/Reports/GetCategoryFromNameId.php +++ b/plugins/Events/Reports/GetCategoryFromNameId.php @@ -19,7 +19,7 @@ class GetCategoryFromNameId extends Report { protected function init() { - $this->category = 'Events_Events'; + $this->categoryId = 'Events_Events'; $this->processedMetrics = false; $this->dimension = new EventCategory(); $this->name = Piwik::translate('Events_EventCategories'); diff --git a/plugins/Events/Reports/GetName.php b/plugins/Events/Reports/GetName.php index aa21f968be..08d97b6ac4 100644 --- a/plugins/Events/Reports/GetName.php +++ b/plugins/Events/Reports/GetName.php @@ -27,6 +27,5 @@ class GetName extends Base $this->actionToLoadSubTables = 'getActionFromNameId'; } $this->order = 2; - $this->widgetTitle = 'Events_EventNames'; } } diff --git a/plugins/Events/Reports/GetNameFromActionId.php b/plugins/Events/Reports/GetNameFromActionId.php index 7b4899b672..4c0325a706 100644 --- a/plugins/Events/Reports/GetNameFromActionId.php +++ b/plugins/Events/Reports/GetNameFromActionId.php @@ -19,7 +19,7 @@ class GetNameFromActionId extends Report { protected function init() { - $this->category = 'Events_Events'; + $this->categoryId = 'Events_Events'; $this->processedMetrics = false; $this->dimension = new EventName(); $this->name = Piwik::translate('Events_Names'); diff --git a/plugins/Events/Reports/GetNameFromCategoryId.php b/plugins/Events/Reports/GetNameFromCategoryId.php index d1f43f7931..6e28ccf1e9 100644 --- a/plugins/Events/Reports/GetNameFromCategoryId.php +++ b/plugins/Events/Reports/GetNameFromCategoryId.php @@ -19,7 +19,7 @@ class GetNameFromCategoryId extends Report { protected function init() { - $this->category = 'Events_Events'; + $this->categoryId = 'Events_Events'; $this->processedMetrics = false; $this->dimension = new EventName(); $this->name = Piwik::translate('Events_EventNames'); diff --git a/plugins/Events/Widgets/EventsByDimension.php b/plugins/Events/Widgets/EventsByDimension.php new file mode 100644 index 0000000000..ef04e0d761 --- /dev/null +++ b/plugins/Events/Widgets/EventsByDimension.php @@ -0,0 +1,22 @@ +addVisitorsItem('Report 1', $this->urlForAction('showList'), $orderId = 30); - // $menu->addActionsItem('Report 1', $this->urlForAction('showList'), $orderId = 30); - - // or create a custom category 'UI Framework' - // $menu->addItem('UI Framework', '', $this->urlForDefaultAction(), $orderId = 30); - // $menu->addItem('UI Framework', 'Report 1', $this->urlForAction('showList'), $orderId = 30); - } public function configureAdminMenu(MenuAdmin $menu) { diff --git a/plugins/ExamplePlugin/Widgets.php b/plugins/ExamplePlugin/Widgets.php deleted file mode 100644 index a5670902ef..0000000000 --- a/plugins/ExamplePlugin/Widgets.php +++ /dev/null @@ -1,67 +0,0 @@ -addWidget('Example Widget Name', $method = 'myExampleWidget'); - // $this->addWidget('Example Widget 2', $method = 'myExampleWidget', $params = array('myparam' => 'myvalue')); - } - - /** - * This method renders a widget as defined in "init()". It's on you how to generate the content of the - * widget. As long as you return a string everything is fine. You can use for instance a "Piwik\View" to render a - * twig template. In such a case don't forget to create a twig template (eg. myViewTemplate.twig) in the - * "templates" directory of your plugin. - * - * @return string - */ - public function myExampleWidget() - { - // $view = new View('@ExamplePlugin/myViewTemplate'); - // return $view->render(); - - return 'My Widget Text'; - } - - /** - * Here you can remove any widgets defined by any plugin. - * - * @param WidgetsList $widgetsList - */ - public function configureWidgetsList(WidgetsList $widgetsList) - { - // $widgetsList->remove('NameOfWidgetCategory'); // will remove all widgets having this category - // $widgetsList->remove('NameOfWidgetCategory', 'Widget name'); // will only remove a specific widget - } -} diff --git a/plugins/ExamplePlugin/Widgets/MyExampleWidget.php b/plugins/ExamplePlugin/Widgets/MyExampleWidget.php new file mode 100644 index 0000000000..687ee6df67 --- /dev/null +++ b/plugins/ExamplePlugin/Widgets/MyExampleWidget.php @@ -0,0 +1,80 @@ +setCategoryId('Example Widgets'); + + /** + * Set the subcategory the widget belongs to. If a subcategory is set, the widget will be shown in the UI. + */ + // $config->setSubcategoryId('General_Overview'); + + /** + * Set the name of the widget belongs to. + */ + $config->setName('Example Widget Name'); + + /** + * Set the order of the widget. The lower the number, the earlier the widget will be listed within a category. + */ + $config->setOrder(99); + + /** + * Optionally set URL parameters that will be used when this widget is requested. + * $config->setParameters(array('myparam' => 'myvalue')); + */ + + /** + * Define whether a widget is enabled or not. For instance some widgets might not be available to every user or + * might depend on a setting (such as Ecommerce) of a site. In such a case you can perform any checks and then + * set `true` or `false`. If your widget is only available to users having super user access you can do the + * following: + * + * $config->setIsEnabled(\Piwik\Piwik::hasUserSuperUserAccess()); + * or + * if (!\Piwik\Piwik::hasUserSuperUserAccess()) + * $config->disable(); + */ + } + + /** + * This method renders the widget. It's on you how to generate the content of the widget. + * As long as you return a string everything is fine. You can use for instance a "Piwik\View" to render a + * twig template. In such a case don't forget to create a twig template (eg. myViewTemplate.twig) in the + * "templates" directory of your plugin. + * + * @return string + */ + public function render() + { + // $view = new View('@ExamplePlugin/myViewTemplate'); + // return $view->render(); + + return '
    My Widget Text
    '; + } + +} \ No newline at end of file diff --git a/plugins/ExampleReport/Reports/Base.php b/plugins/ExampleReport/Reports/Base.php index c09da78e4b..35af935d9e 100644 --- a/plugins/ExampleReport/Reports/Base.php +++ b/plugins/ExampleReport/Reports/Base.php @@ -14,6 +14,6 @@ abstract class Base extends Report { protected function init() { - $this->category = 'ExampleCategory'; + $this->categoryId = 'ExampleCategory'; } } diff --git a/plugins/ExampleReport/Reports/GetExampleReport.php b/plugins/ExampleReport/Reports/GetExampleReport.php index 42af54d04a..9e0980f050 100644 --- a/plugins/ExampleReport/Reports/GetExampleReport.php +++ b/plugins/ExampleReport/Reports/GetExampleReport.php @@ -49,12 +49,8 @@ class GetExampleReport extends Base // 24 rows for 1-24hours // $this->constantRowsCount = true; - // If a menu title is specified, the report will be displayed in the menu - // $this->menuTitle = 'ExampleReportName'; - - // If a widget title is specified, the report will be displayed in the list of widgets and the report can be - // exported as a widget - // $this->widgetTitle = 'ExampleReportName'; + // If a subcategory is specified, the report will be displayed in the menu under this menu item + // $this->subCategory = 'ExampleReportName'; } /** diff --git a/plugins/ExampleRssWidget/Widgets.php b/plugins/ExampleRssWidget/Widgets.php deleted file mode 100644 index 5fc0667fa8..0000000000 --- a/plugins/ExampleRssWidget/Widgets.php +++ /dev/null @@ -1,63 +0,0 @@ -addWidget('Piwik.org Blog', 'rssPiwik'); - $this->addWidget('Piwik Changelog', 'rssChangelog'); - } - - public function rssPiwik() - { - try { - $rss = new RssRenderer('http://feeds.feedburner.com/Piwik'); - $rss->showDescription(true); - - return $rss->get(); - - } catch (\Exception $e) { - - return $this->error($e); - } - } - - public function rssChangelog() - { - try { - $rss = new RssRenderer('http://feeds.feedburner.com/PiwikReleases'); - $rss->setCountPosts(1); - $rss->showDescription(true); - $rss->showContent(false); - - return $rss->get(); - - } catch (\Exception $e) { - - return $this->error($e); - } - } - - /** - * @param \Exception $e - * @return string - */ - private function error($e) - { - return '
    ' - . Piwik::translate('General_ErrorRequest', array('', '')) - . ' - ' . $e->getMessage() . '
    '; - } -} diff --git a/plugins/ExampleRssWidget/Widgets/RssChangelog.php b/plugins/ExampleRssWidget/Widgets/RssChangelog.php new file mode 100644 index 0000000000..70ba5eb0c0 --- /dev/null +++ b/plugins/ExampleRssWidget/Widgets/RssChangelog.php @@ -0,0 +1,49 @@ +setCategoryId('Example Widgets'); + $config->setName('Piwik Changelog'); + } + + public function render() + { + try { + $rss = new RssRenderer('http://feeds.feedburner.com/PiwikReleases'); + $rss->setCountPosts(1); + $rss->showDescription(true); + $rss->showContent(false); + + return $rss->get(); + + } catch (\Exception $e) { + + return $this->error($e); + } + } + + /** + * @param \Exception $e + * @return string + */ + private function error($e) + { + return '
    ' + . Piwik::translate('General_ErrorRequest', array('', '')) + . ' - ' . $e->getMessage() . '
    '; + } +} diff --git a/plugins/ExampleRssWidget/Widgets/RssPiwik.php b/plugins/ExampleRssWidget/Widgets/RssPiwik.php new file mode 100644 index 0000000000..c3c7c76a16 --- /dev/null +++ b/plugins/ExampleRssWidget/Widgets/RssPiwik.php @@ -0,0 +1,47 @@ +setCategoryId('Example Widgets'); + $config->setName('Piwik.org Blog'); + } + + public function render() + { + try { + $rss = new RssRenderer('http://feeds.feedburner.com/Piwik'); + $rss->showDescription(true); + + return $rss->get(); + + } catch (\Exception $e) { + + return $this->error($e); + } + } + + /** + * @param \Exception $e + * @return string + */ + private function error($e) + { + return '
    ' + . Piwik::translate('General_ErrorRequest', array('', '')) + . ' - ' . $e->getMessage() . '
    '; + } +} diff --git a/plugins/ExampleUI/API.php b/plugins/ExampleUI/API.php index 7b6e0c508a..ae9beae05f 100644 --- a/plugins/ExampleUI/API.php +++ b/plugins/ExampleUI/API.php @@ -99,4 +99,5 @@ class API extends \Piwik\Plugin\API return $planetsDataTable; } + } diff --git a/plugins/ExampleUI/Categories/ExampleUiCategory.php b/plugins/ExampleUI/Categories/ExampleUiCategory.php new file mode 100644 index 0000000000..cc7d2fd219 --- /dev/null +++ b/plugins/ExampleUI/Categories/ExampleUiCategory.php @@ -0,0 +1,17 @@ +pluginName . '.' . __FUNCTION__; - $apiAction = 'ExampleUI.getTemperatures'; - - $view = ViewDataTableFactory::build('table', $apiAction, $controllerAction); - - $view->config->translations['value'] = 'Temperature in °C'; - $view->config->translations['label'] = 'Hour of day'; - $view->requestConfig->filter_sort_column = 'label'; - $view->requestConfig->filter_sort_order = 'asc'; - $view->requestConfig->filter_limit = 24; - $view->config->columns_to_display = array('label', 'value'); - $view->config->y_axis_unit = '°C'; // useful if the user requests the bar graph - $view->config->show_exclude_low_population = false; - $view->config->show_table_all_columns = false; - $view->config->disable_row_evolution = true; - $view->config->max_graph_elements = 24; - $view->config->metrics_documentation = array('value' => 'Documentation for temperature metric'); - - return $view->render(); - } - - public function evolutionGraph() - { - $view = new View('@ExampleUI/evolutiongraph'); - - $this->setPeriodVariablesView($view); - $view->evolutionGraph = $this->getEvolutionGraph(array(), array('server1', 'server2')); - - return $view->render(); - } public function notifications() { @@ -78,126 +46,4 @@ class Controller extends \Piwik\Plugin\Controller return $view->render(); } - public function getEvolutionGraph(array $columns = array(), array $defaultColumns = array()) - { - if (empty($columns)) { - $columns = Common::getRequestVar('columns', false); - if (false !== $columns) { - $columns = Piwik::getArrayFromApiParameter($columns); - } - } - - $view = $this->getLastUnitGraphAcrossPlugins($this->pluginName, __FUNCTION__, $columns, - $selectableColumns = array('server1', 'server2'), 'My documentation', 'ExampleUI.getTemperaturesEvolution'); - $view->requestConfig->filter_sort_column = 'label'; - $view->requestConfig->filter_sort_order = 'asc'; - - if (empty($view->config->columns_to_display) && !empty($defaultColumns)) { - $view->config->columns_to_display = $defaultColumns; - } - - return $this->renderView($view); - } - - public function barGraph() - { - $view = ViewDataTableFactory::build( - 'graphVerticalBar', 'ExampleUI.getTemperatures', $controllerAction = 'ExampleUI.barGraph'); - - $view->config->y_axis_unit = '°C'; - $view->config->show_footer = false; - $view->config->translations['value'] = "Temperature"; - $view->config->selectable_columns = array("value"); - $view->config->max_graph_elements = 24; - - return $view->render(); - } - - public function pieGraph() - { - $view = ViewDataTableFactory::build( - 'graphPie', 'ExampleUI.getPlanetRatios', $controllerAction = 'ExampleUI.pieGraph'); - - $view->config->columns_to_display = array('value'); - $view->config->translations['value'] = "times the diameter of Earth"; - $view->config->show_footer_icons = false; - $view->config->selectable_columns = array("value"); - $view->config->max_graph_elements = 10; - - return $view->render(); - } - - public function tagClouds() - { - $output = "

    Simple tag cloud

    "; - $output .= $this->echoSimpleTagClouds(); - - $output .= "

    Advanced tag cloud: with logos and links

    -
      -
    • The logo size is proportional to the value returned by the API
    • -
    • The logo is linked to a specific URL
    • -


    "; - $output .= $this->echoAdvancedTagClouds(); - - return $output; - } - - public function echoSimpleTagClouds() - { - $view = ViewDataTableFactory::build( - 'cloud', 'ExampleUI.getPlanetRatios', $controllerAction = 'ExampleUI.echoSimpleTagClouds'); - - $view->config->columns_to_display = array('label', 'value'); - $view->config->translations['value'] = "times the diameter of Earth"; - $view->config->show_footer = false; - - return $view->render(); - } - - public function echoAdvancedTagClouds() - { - $view = ViewDataTableFactory::build( - 'cloud', 'ExampleUI.getPlanetRatiosWithLogos', $controllerAction = 'ExampleUI.echoAdvancedTagClouds'); - - $view->config->display_logo_instead_of_label = true; - $view->config->columns_to_display = array('label', 'value'); - $view->config->translations['value'] = "times the diameter of Earth"; - - return $view->render(); - } - - public function sparklines() - { - $view = new View('@ExampleUI/sparklines'); - $view->urlSparkline1 = $this->getUrlSparkline('generateSparkline', array('server' => 'server1', 'rand' => mt_rand())); - $view->urlSparkline2 = $this->getUrlSparkline('generateSparkline', array('server' => 'server2', 'rand' => mt_rand())); - - return $view->render(); - } - - public function generateSparkline() - { - $view = ViewDataTableFactory::build( - 'sparkline', 'ExampleUI.getTemperaturesEvolution', $controllerAction = 'ExampleUI.generateSparkline'); - - $serverRequested = Common::getRequestVar('server', false); - if (false !== $serverRequested) { - $view->config->columns_to_display = array($serverRequested); - } - - return $view->render(); - } - - public function treemap() - { - $view = ViewDataTableFactory::build( - 'infoviz-treemap', 'ExampleUI.getTemperatures', $controllerAction = 'ExampleUI.treemap'); - - $view->config->translations['value'] = "Temperature"; - $view->config->columns_to_display = array("label", "value"); - $view->config->selectable_columns = array("value"); - $view->config->show_evolution_values = 0; - - return $view->render(); - } } diff --git a/plugins/ExampleUI/Menu.php b/plugins/ExampleUI/Menu.php index e25bd10817..35cf0d70b5 100644 --- a/plugins/ExampleUI/Menu.php +++ b/plugins/ExampleUI/Menu.php @@ -8,37 +8,12 @@ */ namespace Piwik\Plugins\ExampleUI; -use Piwik\Menu\MenuReporting; use Piwik\Menu\MenuUser; -use Piwik\Plugin\Manager as PluginManager; -/** - */ class Menu extends \Piwik\Plugin\Menu { - public function configureReportingMenu(MenuReporting $menu) - { - $menu->addItem('UI Framework', '', $this->urlForAction('dataTables'), 30); - - $this->addSubMenu($menu, 'Data tables', 'dataTables', 1); - $this->addSubMenu($menu, 'Bar graph', 'barGraph', 2); - $this->addSubMenu($menu, 'Pie graph', 'pieGraph', 3); - $this->addSubMenu($menu, 'Tag clouds', 'tagClouds', 4); - $this->addSubMenu($menu, 'Sparklines', 'sparklines', 5); - $this->addSubMenu($menu, 'Evolution Graph', 'evolutionGraph', 6); - - if (PluginManager::getInstance()->isPluginActivated('TreemapVisualization')) { - $this->addSubMenu($menu, 'Treemap', 'treemap', 7); - } - } - public function configureUserMenu(MenuUser $menu) { $menu->addPlatformItem('UI Notifications', $this->urlForAction('notifications'), $order = 10); } - - private function addSubMenu(MenuReporting $menu, $subMenu, $action, $order) - { - $menu->addItem('UI Framework', $subMenu, $this->urlForAction($action), $order); - } } diff --git a/plugins/ExampleUI/Reports/Base.php b/plugins/ExampleUI/Reports/Base.php new file mode 100644 index 0000000000..88fa676754 --- /dev/null +++ b/plugins/ExampleUI/Reports/Base.php @@ -0,0 +1,19 @@ +categoryId = 'ExampleUI_UiFramework'; + } +} diff --git a/plugins/ExampleUI/Reports/GetPlanetRatios.php b/plugins/ExampleUI/Reports/GetPlanetRatios.php new file mode 100644 index 0000000000..244e8f79c8 --- /dev/null +++ b/plugins/ExampleUI/Reports/GetPlanetRatios.php @@ -0,0 +1,74 @@ +name = 'Pie graph'; + $this->subcategoryId = $this->name; + $this->order = 112; + } + + public function getDefaultTypeViewDataTable() + { + return PIE::ID; + } + + public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory) + { + $widgetsList->addWidgetConfig( + // in this case it will render PIE as configured as default + $factory->createWidget() + ); + + $widgetsList->addWidgetConfig( + $factory->createWidget() + ->setName('Simple tag cloud') + ->setSubcategoryId('Tag clouds') + ->forceViewDataTable(Cloud::ID) + ->setOrder(5) + ); + } + + public function configureView(ViewDataTable $view) + { + $view->config->addTranslation('value', 'times the diameter of Earth'); + + if ($view->isViewDataTableId(PIE::ID)) { + + $view->config->columns_to_display = array('value'); + $view->config->selectable_columns = array('value'); + $view->config->show_footer_icons = false; + $view->config->max_graph_elements = 10; + + } else if ($view->isViewDataTableId(Cloud::ID)) { + + $view->config->columns_to_display = array('label', 'value'); + $view->config->show_footer = false; + + } + } + +} diff --git a/plugins/ExampleUI/Reports/GetPlanetRatiosWithLogos.php b/plugins/ExampleUI/Reports/GetPlanetRatiosWithLogos.php new file mode 100644 index 0000000000..d4d205e6c9 --- /dev/null +++ b/plugins/ExampleUI/Reports/GetPlanetRatiosWithLogos.php @@ -0,0 +1,44 @@ +name = Piwik::translate('Advanced tag cloud: with logos and links'); + $this->subcategoryId = 'Tag clouds'; + $this->order = 113; + } + + public function getDefaultTypeViewDataTable() + { + return Cloud::ID; + } + + public function configureView(ViewDataTable $view) + { + $view->config->display_logo_instead_of_label = true; + $view->config->columns_to_display = array('label', 'value'); + $view->config->addTranslation('value', 'times the diameter of Earth'); + } + +} diff --git a/plugins/ExampleUI/Reports/GetTemperatures.php b/plugins/ExampleUI/Reports/GetTemperatures.php new file mode 100644 index 0000000000..0449e8b3e2 --- /dev/null +++ b/plugins/ExampleUI/Reports/GetTemperatures.php @@ -0,0 +1,93 @@ +name = Piwik::translate('ExampleUI_GetTemperaturesDataTable'); + $this->subcategoryId = 'ExampleUI_GetTemperaturesDataTable'; + $this->order = 110; + } + + public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory) + { + // this will render the default view, in this case an Html Table + $widgetsList->addWidgetConfig($factory->createWidget()); + + $widgetsList->addWidgetConfig( + $factory->createWidget() + ->forceViewDataTable(Bar::ID) + ->setSubcategoryId('Bar graph') + ); + + if (PluginManager::getInstance()->isPluginActivated('TreemapVisualization')) { + $widgetsList->addWidgetConfig( + $factory->createWidget() + ->setName('Treemap example') + ->setSubcategoryId('Treemap') + ->forceViewDataTable('infoviz-treemap') + ); + + } + } + + public function configureView(ViewDataTable $view) + { + if ($view->isViewDataTableId(BAR::ID)) { + + $view->config->y_axis_unit = '°C'; + $view->config->show_footer = false; + $view->config->translations['value'] = "Temperature"; + $view->config->selectable_columns = array("value"); + $view->config->max_graph_elements = 24; + + } elseif ($view->isViewDataTableId('infoviz-treemap')) { + + $view->config->translations['value'] = "Temperature"; + $view->config->columns_to_display = array("label", "value"); + $view->config->selectable_columns = array("value"); + $view->config->show_evolution_values = 0; + + } else { + // for default view datatable, eg HtmlTable + + $view->config->translations['value'] = 'Temperature in °C'; + $view->config->translations['label'] = 'Hour of day'; + $view->requestConfig->filter_sort_column = 'label'; + $view->requestConfig->filter_sort_order = 'asc'; + $view->requestConfig->filter_limit = 24; + $view->config->columns_to_display = array('label', 'value'); + $view->config->y_axis_unit = '°C'; // useful if the user requests the bar graph + $view->config->show_exclude_low_population = false; + $view->config->show_table_all_columns = false; + $view->config->disable_row_evolution = true; + $view->config->max_graph_elements = 24; + $view->config->metrics_documentation = array('value' => 'Documentation for temperature metric'); + } + } + +} diff --git a/plugins/ExampleUI/Reports/GetTemperaturesEvolution.php b/plugins/ExampleUI/Reports/GetTemperaturesEvolution.php new file mode 100644 index 0000000000..ff8ea66e10 --- /dev/null +++ b/plugins/ExampleUI/Reports/GetTemperaturesEvolution.php @@ -0,0 +1,95 @@ +name = Piwik::translate('ExampleUI_GetTemperaturesEvolution'); + $this->order = 111; + } + + public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory) + { + $widgetsList->addWidgetConfig( + $factory->createWidget() + ->setSubcategoryId('Sparklines') + ->forceViewDataTable(Sparklines::ID) + ); + + $widgetsList->addWidgetConfig( + $factory->createWidget() + ->setName('ExampleUI_TemperaturesEvolution') + ->setSubcategoryId('Evolution Graph') + ->forceViewDataTable(Evolution::ID) + ->setParameters(array('columns' => array('server1', 'server2'))) + ); + + } + + /** + * Here you can configure how your report should be displayed. For instance whether your report supports a search + * etc. You can also change the default request config. For instance change how many rows are displayed by default. + * + * @param ViewDataTable $view + */ + public function configureView(ViewDataTable $view) + { + if ($view->isViewDataTableId(Sparklines::ID)) { + + /** @var Sparklines $view */ + $view->config->addSparklineMetric(array('server1')); + $view->config->addSparklineMetric(array('server2')); + $view->config->addTranslations(array('server1' => 'Evolution of temperature for server piwik.org')); + $view->config->addTranslations(array('server2' => 'Evolution of temperature for server dev.piwik.org')); + + } elseif ($view->isViewDataTableId(Evolution::ID)) { + + /** @var Evolution $view */ + $selectableColumns = array('server1', 'server2'); + + $columns = Common::getRequestVar('columns', false); + if (!empty($columns)) { + $columns = Piwik::getArrayFromApiParameter($columns); + } + + $columns = array_merge($columns ? $columns : array(), $selectableColumns); + $view->config->columns_to_display = $columns; + + $view->config->addTranslations(array_combine($columns, $columns)); + $view->config->selectable_columns = $selectableColumns; + $view->requestConfig->filter_sort_column = 'label'; + $view->requestConfig->filter_sort_order = 'asc'; + $view->config->documentation = 'My documentation'; + $view->config->show_goals = false; + } + } + +} diff --git a/plugins/ExampleUI/lang/en.json b/plugins/ExampleUI/lang/en.json new file mode 100644 index 0000000000..e0c05c5411 --- /dev/null +++ b/plugins/ExampleUI/lang/en.json @@ -0,0 +1,8 @@ +{ + "ExampleUI": { + "UiFramework": "UI Framework", + "GetTemperaturesDataTable": "Data tables", + "GetTemperaturesEvolution": "Temperatures evolution over time", + "TemperaturesEvolution": "Evolution of server temperatures over the last few days" + } +} \ No newline at end of file diff --git a/plugins/ExampleUI/plugin.json b/plugins/ExampleUI/plugin.json index ec2fcfe025..8a39e0a2a2 100644 --- a/plugins/ExampleUI/plugin.json +++ b/plugins/ExampleUI/plugin.json @@ -2,14 +2,23 @@ "name": "ExampleUI", "description": "Piwik Platform showcase: how to display data tables, graphs, and the UI framework.", "version": "1.0.1", - "keywords": ["example", "framework", "platform", "ui", "visualization"], - "homepage": "http://piwik.org", + "keywords": [ + "example", + "framework", + "platform", + "ui", + "visualization" + ], + "homepage": "http:\/\/piwik.org", "license": "GPL v3+", "authors": [ { "name": "Piwik", "email": "hello@piwik.org", - "homepage": "http://piwik.org" + "homepage": "http:\/\/piwik.org" } - ] + ], + "require": { + "piwik": ">=2.13.1" + } } \ No newline at end of file diff --git a/plugins/Goals/API.php b/plugins/Goals/API.php index 80a898fe34..351e700782 100644 --- a/plugins/Goals/API.php +++ b/plugins/Goals/API.php @@ -22,6 +22,7 @@ use Piwik\Plugin\Report; use Piwik\Plugins\API\DataTable\MergeDataTables; use Piwik\Plugins\CoreHome\Columns\Metrics\ConversionRate; use Piwik\Plugins\Goals\Columns\Metrics\AverageOrderRevenue; +use Piwik\Plugin\Reports; use Piwik\Segment\SegmentExpression; use Piwik\Site; use Piwik\Tracker\Cache; @@ -414,7 +415,7 @@ class API extends \Piwik\Plugin\API $requestedColumns = array_unique(array_merge($requestedColumns, $metricsToAdd)); } - $report = Report::factory('Goals', 'getMetrics'); + $report = Reports::factory('Goals', 'getMetrics'); $columnsToGet = $report->getMetricsRequiredForReport($allMetrics, $requestedColumns); $inDbMetricNames = array_map(function ($name) use ($idGoal) { diff --git a/plugins/Goals/Categories/AddANewGoalSubcategory.php b/plugins/Goals/Categories/AddANewGoalSubcategory.php new file mode 100644 index 0000000000..9b613f2e55 --- /dev/null +++ b/plugins/Goals/Categories/AddANewGoalSubcategory.php @@ -0,0 +1,19 @@ +translator = $translator; - $this->translationHelper = $translationHelper; $this->idSite = Common::getRequestVar('idSite', null, 'int'); $this->goals = API::getInstance()->getGoals($this->idSite); } - public function widgetGoalReport() - { - $view = $this->getGoalReportView($idGoal = Common::getRequestVar('idGoal', null, 'string')); - $view->displayFullReport = false; - return $view->render(); - } - - public function goalReport() - { - $view = $this->getGoalReportView($idGoal = Common::getRequestVar('idGoal', null, 'string')); - $view->displayFullReport = true; - return $view->render(); - } - - protected function getGoalReportView($idGoal = false) - { - $view = new View('@Goals/getGoalReportView'); - if ($idGoal == Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER) { - $goalDefinition['name'] = $this->translator->translate('Goals_Ecommerce'); - $goalDefinition['allow_multiple'] = true; - $ecommerce = $view->ecommerce = true; - } else { - if (!isset($this->goals[$idGoal])) { - Piwik::redirectToModule('Goals', 'index', array('idGoal' => null)); - } - $goalDefinition = $this->goals[$idGoal]; - } - $this->setGeneralVariablesView($view); - $goal = $this->getMetricsForGoal($idGoal); - foreach ($goal as $name => $value) { - $view->$name = $value; - } - if ($idGoal == Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER) { - $goal = $this->getMetricsForGoal(Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_CART); - foreach ($goal as $name => $value) { - $name = 'cart_' . $name; - $view->$name = $value; - } - } - $view->showHeadline = false; - $view->idGoal = $idGoal; - $view->goalName = $goalDefinition['name']; - $view->goalAllowMultipleConversionsPerVisit = $goalDefinition['allow_multiple']; - $view->graphEvolution = $this->getEvolutionGraph(array(), $idGoal, array('nb_conversions')); - $view->nameGraphEvolution = 'Goals.getEvolutionGraph' . $idGoal; - $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->goalReportsByDimension = $this->getGoalReportsByDimensionTable( - $view->nb_conversions, isset($ecommerce), !empty($view->cart_nb_conversions)); - return $view; - } - - public function index() - { - $view = $this->getOverviewView(); - - // unsanitize goal names and other text data (not done in API so as not to break - // any other code/cause security issues) - $goals = $this->goals; - $view->goalsJSON = json_encode($goals); - - $view->ecommerceEnabled = $this->site->isEcommerceEnabled(); - $view->displayFullReport = true; - return $view->render(); - } - public function manage() { Piwik::checkUserHasAdminAccess($this->idSite); @@ -164,48 +86,20 @@ class Controller extends \Piwik\Plugin\Controller return $view->render(); } - public function widgetGoalsOverview() + public function goalConversionsOverview() { - $view = $this->getOverviewView(); - $view->displayFullReport = false; - return $view->render(); - } + $view = new View('@Goals/conversionOverview'); + $idGoal = Common::getRequestVar('idGoal', null, 'string'); - protected function getOverviewView() - { - $view = new View('@Goals/getOverviewView'); - $this->setGeneralVariablesView($view); - - $view->graphEvolution = $this->getEvolutionGraph(array(), false, array('nb_conversions')); - $view->nameGraphEvolution = 'GoalsgetEvolutionGraph'; - - // sparkline for the historical data of the above values - $view->urlSparklineConversions = $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('nb_conversions'), 'idGoal' => '')); - $view->urlSparklineConversionRate = $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('conversion_rate'), 'idGoal' => '')); - $view->urlSparklineRevenue = $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('revenue'), 'idGoal' => '')); - - // Pass empty idGoal will return Goal overview - $request = new Request("method=Goals.get&format=original&idGoal="); - $datatable = $request->process(); - $dataRow = $datatable->getFirstRow(); + $view->topDimensions = $this->getTopDimensions($idGoal); - $view->nb_conversions = $dataRow->getColumn('nb_conversions'); - $view->nb_visits_converted = $dataRow->getColumn('nb_visits_converted'); - $view->conversion_rate = $this->formatConversionRate($dataRow->getColumn('conversion_rate')); - $view->revenue = $dataRow->getColumn('revenue'); + $goalMetrics = Request::processRequest('Goals.get', array('idGoal' => $idGoal)); - $goalMetrics = array(); - foreach ($this->goals as $idGoal => $goal) { - $goalMetrics[$idGoal] = $this->getMetricsForGoal($idGoal); - $goalMetrics[$idGoal]['name'] = $goal['name']; - $goalMetrics[$idGoal]['goalAllowMultipleConversionsPerVisit'] = $goal['allow_multiple']; - } + // 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->goalMetrics = $goalMetrics; - $view->goals = $this->goals; - $view->goalReportsByDimension = $this->getGoalReportsByDimensionTable( - $view->nb_conversions, $ecommerce = false, !empty($view->cart_nb_conversions)); - return $view; + return $view->render(); } public function getLastNbConversionsGraph() @@ -244,6 +138,26 @@ class Controller extends \Piwik\Plugin\Controller 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)) { @@ -334,11 +248,11 @@ class Controller extends \Piwik\Plugin\Controller $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" . + &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(); @@ -402,72 +316,11 @@ class Controller extends \Piwik\Plugin\Controller '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; } - /** - * Utility function that returns HTML that displays Goal information for reports. This - * is the HTML that is at the bottom of every goals page. - * - * @param int $conversions The number of conversions for this goal (or all goals - * in case of the overview). - * @param bool $ecommerce Whether to show ecommerce reports or not. - * @param bool $cartNbConversions Whether there are cart conversions or not for this - * goal. - * @return string - */ - private function getGoalReportsByDimensionTable($conversions, $ecommerce = false, $cartNbConversions = false) - { - $preloadAbandonedCart = $cartNbConversions !== false && $conversions == 0; - - $goalReportsByDimension = new ReportsByDimension('Goals'); - - // add ecommerce reports - $ecommerceCustomParams = array(); - if ($ecommerce) { - if ($preloadAbandonedCart) { - $ecommerceCustomParams['abandonedCarts'] = '1'; - } else { - $ecommerceCustomParams['abandonedCarts'] = '0'; - } - } - - if ($conversions > 0 || $ecommerce) { - // for non-Goals reports, we show the goals table - $customParams = $ecommerceCustomParams + array('documentationForGoalsPage' => '1'); - - if (Common::getRequestVar('idGoal', '') === '') // if no idGoal, use 0 for overview - { - $customParams['idGoal'] = '0'; // NOTE: Must be string! Otherwise Piwik_View_HtmlTable_Goals fails. - } - - $allReports = Goals::getReportsWithGoalMetrics(); - foreach ($allReports as $category => $reports) { - if ($ecommerce) { - $categoryText = $this->translationHelper->translateEcommerceMetricCategory($category); - } else { - $categoryText = $this->translationHelper->translateGoalMetricCategory($category); - } - - foreach ($reports as $report) { - if (empty($report['viewDataTable']) - && empty($report['abandonedCarts']) - ) { - $report['viewDataTable'] = 'tableGoals'; - } - $customParams['viewDataTable'] = $report['viewDataTable']; - - $goalReportsByDimension->addReport( - $categoryText, $report['name'], $report['module'] . '.' . $report['action'], $customParams); - } - } - } - - return $goalReportsByDimension->render(); - } - private function setEditGoalsViewVariables($view) { $goals = $this->goals; @@ -496,4 +349,32 @@ class Controller extends \Piwik\Plugin\Controller { $view->userCanEditGoals = Piwik::isUserHasAdminAccess($this->idSite); } + + /** + * @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'); + } } diff --git a/plugins/Goals/Conversions.php b/plugins/Goals/Conversions.php new file mode 100644 index 0000000000..fbbbef0078 --- /dev/null +++ b/plugins/Goals/Conversions.php @@ -0,0 +1,45 @@ + $idGoal, + 'period' => $period, + 'date' => $date, + 'idSite' => $idSite, + 'serialize' => 0, + 'segment' => false + )); + + // we ignore the segment even if there is one set. We still want to show conversion overview if there are conversions + // in general but not for this segment + + $dataRow = $datatable->getFirstRow(); + + if (!$dataRow) { + return false; + } + + return $dataRow->getColumn('nb_conversions'); + } +} diff --git a/plugins/Goals/Goals.php b/plugins/Goals/Goals.php index d26e2cf77e..609d98c419 100644 --- a/plugins/Goals/Goals.php +++ b/plugins/Goals/Goals.php @@ -13,8 +13,9 @@ use Piwik\Common; use Piwik\Db; use Piwik\Piwik; use Piwik\Plugin\Report; +use Piwik\Plugin\Reports; use Piwik\Tracker\GoalManager; -use Piwik\Translate; +use Piwik\Category\Subcategory; /** * @@ -29,36 +30,17 @@ class Goals extends \Piwik\Plugin foreach ($dimensions as $dimension) { $group = $dimension['category']; // move "Custom Variables" report to the "Goals/Sales by User attribute" category - if ($dimension['module'] === 'CustomVariables') { + if ($dimension['module'] === 'CustomVariables' + || $dimension['action'] == 'getVisitInformationPerServerTime') { $group = 'VisitsSummary_VisitsSummary'; } unset($dimension['category']); $dimensionsByGroup[$group][] = $dimension; } - uksort($dimensionsByGroup, array('self', 'sortGoalDimensionsByModule')); return $dimensionsByGroup; } - public static function sortGoalDimensionsByModule($a, $b) - { - static $order = null; - - if (is_null($order)) { - $order = array( - 'Referrers_Referrers', - 'General_Visit', - 'General_Visitors', - 'VisitsSummary_VisitsSummary', - 'VisitTime_ColumnServerTime', - ); - } - - $orderA = array_search($a, $order); - $orderB = array_search($b, $order); - return $orderA > $orderB; - } - public static function getGoalColumns($idGoal) { $columns = array( @@ -98,11 +80,34 @@ class Goals extends \Piwik\Plugin 'SitesManager.deleteSite.end' => 'deleteSiteGoals', 'Goals.getReportsWithGoalMetrics' => 'getActualReportsWithGoalMetrics', 'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys', - 'Metrics.getDefaultMetricTranslations' => 'addMetricTranslations' + 'Metrics.getDefaultMetricTranslations' => 'addMetricTranslations', + 'Category.addSubcategories' => 'addSubcategories' ); return $hooks; } + public function addSubcategories(&$subcategories) + { + $idSite = Common::getRequestVar('idSite', 0, 'int'); + + if (!$idSite) { + return; + } + + $goals = API::getInstance()->getGoals($idSite); + + $order = 900; + foreach ($goals as $goal) { + $category = new Subcategory(); + $category->setName($goal['name']); + $category->setCategoryId('Goals_Goals'); + $category->setId($goal['idgoal']); + $category->setOrder($order++); + $subcategories[] = $category; + } + } + + public function addMetricTranslations(&$translations) { $metrics = array( @@ -176,10 +181,12 @@ class Goals extends \Piwik\Plugin { $reportsWithGoals = array(); - foreach (Report::getAllReports() as $report) { + $reports = new Reports(); + + foreach ($reports->getAllReports() as $report) { if ($report->hasGoalMetrics()) { $reportsWithGoals[] = array( - 'category' => $report->getCategoryKey(), + 'category' => $report->getCategoryId(), 'name' => $report->getName(), 'module' => $report->getModule(), 'action' => $report->getAction(), @@ -271,5 +278,6 @@ class Goals extends \Piwik\Plugin $translationKeys[] = 'Goals_DeleteGoalConfirm'; $translationKeys[] = 'Goals_Ecommerce'; $translationKeys[] = 'Goals_Optional'; + $translationKeys[] = 'Goals_ChooseGoal'; } } diff --git a/plugins/Goals/Menu.php b/plugins/Goals/Menu.php index 85db036797..503c7e0430 100644 --- a/plugins/Goals/Menu.php +++ b/plugins/Goals/Menu.php @@ -10,7 +10,6 @@ namespace Piwik\Plugins\Goals; use Piwik\Common; use Piwik\Menu\Group; -use Piwik\Menu\MenuReporting; use Piwik\Menu\MenuUser; use Piwik\Piwik; use Piwik\Plugins\UsersManager\UserPreferences; @@ -18,48 +17,6 @@ use Piwik\Translate; class Menu extends \Piwik\Plugin\Menu { - public function configureReportingMenu(MenuReporting $menu) - { - $idSite = $this->getIdSite(); - $goals = API::getInstance()->getGoals($idSite); - $mainGoalMenu = 'Goals_Goals'; - - if (count($goals) == 0) { - $linkToAddNewGoal = $this->urlForAction('addNewGoal', array( - 'idGoal' => null, - )); - $menu->addItem($mainGoalMenu, '', $linkToAddNewGoal, 25); - $menu->addItem($mainGoalMenu, 'Goals_AddNewGoal', $linkToAddNewGoal, 1); - return; - } - - $order = 1; - - $url = $this->urlForAction('index', array('idGoal' => null)); - - $menu->addItem($mainGoalMenu, '', $url, 25); - $menu->addItem($mainGoalMenu, 'General_Overview', $url, ++$order); - - $group = new Group(); - foreach ($goals as $goal) { - $subMenuName = str_replace('%', '%%', Translate::clean($goal['name'])); - $params = $this->urlForAction('goalReport', array('idGoal' => $goal['idgoal'])); - $tooltip = sprintf('%s (id = %d)', $subMenuName, $goal['idgoal']); - - if (count($goals) > 3) { - $group->add($subMenuName, $params, $tooltip); - } else { - $menu->addItem($mainGoalMenu, $subMenuName, $params, ++$order, $tooltip); - } - } - - if (count($goals) > 3) { - $menu->addGroup($mainGoalMenu, 'Goals_ChooseGoal', $group, ++$order, $tooltip = false); - } - - $menu->addItem($mainGoalMenu, 'Goals_ManageGoals', $this->urlForAction('editGoals'), ++$order); - } - public function configureUserMenu(MenuUser $menu) { $userPreferences = new UserPreferences(); diff --git a/plugins/Goals/Pages.php b/plugins/Goals/Pages.php new file mode 100644 index 0000000000..9ab7a96d66 --- /dev/null +++ b/plugins/Goals/Pages.php @@ -0,0 +1,339 @@ +factory = $reportFactory; + $this->allReports = $reportsWithGoalMetrics; + $this->conversions = new Conversions(); + } + + /** + * @param array $goals + * @return WidgetConfig[] + */ + public function createGoalsOverviewPage($goals) + { + $subcategory = 'General_Overview'; + + $widgets = array(); + + $config = $this->factory->createWidget(); + $config->forceViewDataTable(Evolution::ID); + $config->setSubcategoryId($subcategory); + $config->setAction('getEvolutionGraph'); + $config->setOrder(++$this->orderId); + $config->setIsNotWidgetizable(); + $widgets[] = $config; + + $config = $this->factory->createWidget(); + $config->forceViewDataTable(Sparklines::ID); + $config->setSubcategoryId($subcategory); + $config->setName(''); + $config->setOrder(++$this->orderId); + $config->setIsNotWidgetizable(); + $widgets[] = $config; + + foreach ($goals as $goal) { + $name = Common::sanitizeInputValue($goal['name']); + $goalTranslated = Piwik::translate('Goals_GoalX', array($name)); + + $config = $this->factory->createWidget(); + $config->setName($goalTranslated); + $config->setSubcategoryId($subcategory); + $config->forceViewDataTable(Sparklines::ID); + $config->setParameters(array('idGoal' => $goal['idgoal'])); + $config->setOrder(++$this->orderId); + $config->setIsNotWidgetizable(); + $config->addParameters(array('allow_multiple' => (int) $goal['allow_multiple'], 'only_summary' => '1')); + $widgets[] = $config; + } + + $container = $this->createWidgetizableWidgetContainer('GoalsOverview', $subcategory, $widgets); + + $config = $this->factory->createContainerWidget('Goals'); + $config->setSubcategoryId($subcategory); + $config->setName('Goals_ConversionsOverviewBy'); + $config->setOrder(++$this->orderId); + $config->setIsNotWidgetizable(); + $this->buildGoalByDimensionView('', $config); + $config->setMiddlewareParameters(array( + 'module' => 'Goals', + 'action' => 'hasConversions' + )); + + return array($container, $config); + } + + /** + * @return WidgetConfig[] + */ + public function createEcommerceOverviewPage() + { + $category = 'Goals_Ecommerce'; + $subcategory = 'General_Overview'; + $idGoal = Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER; + + $widgets = array(); + $config = $this->factory->createWidget(); + $config->forceViewDataTable(Evolution::ID); + $config->setCategoryId($category); + $config->setSubcategoryId($subcategory); + $config->setAction('getEvolutionGraph'); + $config->setOrder(++$this->orderId); + $config->setIsNotWidgetizable(); + $config->setParameters(array('idGoal' => $idGoal)); + $widgets[] = $config; + + $config = $this->factory->createWidget(); + $config->setCategoryId($category); + $config->forceViewDataTable(Sparklines::ID); + $config->setSubcategoryId($subcategory); + $config->setName(''); + $config->setModule('Ecommerce'); + $config->setAction('getSparklines'); + $config->setParameters(array('idGoal' => $idGoal)); + $config->setOrder(++$this->orderId); + $config->setIsNotWidgetizable(); + $widgets[] = $config; + + $config = $this->factory->createWidget(); + $config->setModule('Ecommerce'); + $config->setAction('getConversionsOverview'); + $config->setSubcategoryId($idGoal); + $config->setName('Goals_ConversionsOverview'); + $config->setParameters(array('idGoal' => $idGoal)); + $config->setOrder(++$this->orderId); + $config->setIsNotWidgetizable(); + $config->setMiddlewareParameters(array( + 'module' => 'Goals', + 'action' => 'hasConversions', + 'idGoal' => $idGoal + )); + + $widgets[] = $config; + + $container = $this->createWidgetizableWidgetContainer('EcommerceOverview', $subcategory, $widgets); + return array($container); + } + + /** + * @return WidgetConfig[] + */ + public function createEcommerceSalesPage() + { + $category = 'Goals_Ecommerce'; + $subcategory = 'Ecommerce_Sales'; + + $config = $this->factory->createContainerWidget('GoalsOrder'); + $config->setCategoryId($category); + $config->setSubcategoryId($subcategory); + $config->setName(''); + $config->setParameters(array('idGoal' => Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER)); + $config->setOrder(++$this->orderId); + $config->setIsNotWidgetizable(); + $this->buildGoalByDimensionView(Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER, $config); + + return array($config); + } + + /** + * @param array $goal + * @return WidgetConfig[] + */ + public function createGoalDetailPage($goal) + { + $widgets = array(); + + $idGoal = (int) $goal['idgoal']; + $name = Common::sanitizeInputValue($goal['name']); + $params = array('idGoal' => $idGoal); + + $config = $this->factory->createWidget(); + $config->setSubcategoryId($idGoal); + $config->forceViewDataTable(Evolution::ID); + $config->setAction('getEvolutionGraph'); + $config->setParameters($params); + $config->setOrder(++$this->orderId); + $config->setIsNotWidgetizable(); + $widgets[] = $config; + + $config = $this->factory->createWidget(); + $config->setSubcategoryId($idGoal); + $config->setName(''); + $config->forceViewDataTable(Sparklines::ID); + $config->setParameters($params); + $config->addParameters(array('allow_multiple' => (int) $goal['allow_multiple'])); + $config->setOrder(++$this->orderId); + $config->setIsNotWidgetizable(); + $config->setIsNotWidgetizable(); + $widgets[] = $config; + + $config = $this->factory->createWidget(); + $config->setAction('goalConversionsOverview'); + $config->setSubcategoryId($idGoal); + $config->setName('Goals_ConversionsOverview'); + $config->setParameters($params); + $config->setOrder(++$this->orderId); + $config->setIsNotWidgetizable(); + $config->setMiddlewareParameters(array( + 'module' => 'Goals', + 'action' => 'hasConversions', + 'idGoal' => $idGoal + )); + $widgets[] = $config; + + $container = $this->createWidgetizableWidgetContainer('Goal_' . $idGoal, $name, $widgets); + + $configs = array($container); + + $config = $this->factory->createContainerWidget('Goals' . $idGoal); + $config->setName(Piwik::translate('Goals_GoalConversionsBy', array($name))); + $config->setSubcategoryId($idGoal); + $config->setParameters(array()); + $config->setOrder(++$this->orderId); + $config->setIsNotWidgetizable(); + $config->setMiddlewareParameters(array( + 'module' => 'Goals', + 'action' => 'hasConversions', + 'idGoal' => $idGoal + )); + $this->buildGoalByDimensionView($idGoal, $config); + + $configs[] = $config; + + return $configs; + } + + private function createWidgetizableWidgetContainer($containerId, $pageName, $widgets) + { + /** @var \Piwik\Widget\WidgetConfig[] $widgets */ + $firstWidget = reset($widgets); + /** @var \Piwik\Report\ReportWidgetConfig $firstWidget */ + + if (!empty($pageName)) { + // make sure to not show two titles (one for this container and one for the first widget) + $firstWidget->setName(''); + } + + $config = $this->factory->createContainerWidget($containerId); + $config->setName($pageName); + $config->setCategoryId($firstWidget->getCategoryId()); + $config->setSubcategoryId($firstWidget->getSubcategoryId()); + $config->setIsWidgetizable(); + $config->setOrder($this->orderId++); + + foreach ($widgets as $widget) { + $config->addWidgetConfig($widget); + } + + return $config; + } + + private function buildGoalByDimensionView($idGoal, WidgetContainerConfig $container) + { + $container->setLayout('ByDimension'); + $ecommerce = ($idGoal == Piwik::LABEL_ID_GOAL_IS_ECOMMERCE_ORDER); + + // for non-Goals reports, we show the goals table + $customParams = array('documentationForGoalsPage' => '1'); + + if ($idGoal === '') { + // if no idGoal, use 0 for overview. Must be string! Otherwise Piwik_View_HtmlTable_Goals fails. + $customParams['idGoal'] = '0'; + } else { + $customParams['idGoal'] = $idGoal; + } + + $translationHelper = new TranslationHelper(); + + foreach ($this->allReports as $category => $reports) { + $order = ($this->getSortOrderOfCategory($category) * 100); + + if ($ecommerce) { + $categoryText = $translationHelper->translateEcommerceMetricCategory($category); + } else { + $categoryText = $translationHelper->translateGoalMetricCategory($category); + } + + foreach ($reports as $report) { + $order++; + + if (empty($report['viewDataTable']) + && empty($report['abandonedCarts']) + ) { + $report['viewDataTable'] = 'tableGoals'; + } + + $widget = $this->createWidgetForReport($report['module'], $report['action']); + $widget->setParameters($customParams); + $widget->setCategoryId($categoryText); + $widget->setSubcategoryId($categoryText); + $widget->setOrder($order); + $widget->setIsNotWidgetizable(); + + if (!empty($report['viewDataTable'])) { + $widget->setDefaultViewDataTable($report['viewDataTable']); + } + + $container->addWidgetConfig($widget); + } + } + } + + private function getSortOrderOfCategory($category) + { + static $order = null; + + if (is_null($order)) { + $order = array( + 'Referrers_Referrers', + 'General_Visit', + 'General_Visitors', + 'VisitsSummary_VisitsSummary', + ); + } + + $value = array_search($category, $order); + + if (false === $value) { + $value = count($order) + 1; + } + + return $value; + } + + private function createWidgetForReport($module, $action) + { + $factory = new ReportWidgetFactory(Reports::factory($module, $action)); + return $factory->createWidget(); + } + +} diff --git a/plugins/Goals/Reports/Base.php b/plugins/Goals/Reports/Base.php index fd732035d3..3f9cb9c98a 100644 --- a/plugins/Goals/Reports/Base.php +++ b/plugins/Goals/Reports/Base.php @@ -18,7 +18,7 @@ abstract class Base extends \Piwik\Plugin\Report protected function init() { - $this->category = 'Goals_Goals'; + $this->categoryId = 'Goals_Goals'; } protected function addReportMetadataForEachGoal(&$availableReports, $infos, $goalNameFormatter) diff --git a/plugins/Goals/Reports/Get.php b/plugins/Goals/Reports/Get.php index bccecda146..66f167fb24 100644 --- a/plugins/Goals/Reports/Get.php +++ b/plugins/Goals/Reports/Get.php @@ -8,7 +8,20 @@ */ namespace Piwik\Plugins\Goals\Reports; +use Piwik\Common; +use Piwik\DataTable; +use Piwik\Metrics\Formatter; use Piwik\Piwik; +use Piwik\Plugin; +use Piwik\Plugin\ViewDataTable; +use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Evolution; +use Piwik\Plugins\CoreVisualizations\Visualizations\Sparklines; +use Piwik\Plugins\Goals\API; +use Piwik\Plugins\Goals\Goals; +use Piwik\Plugins\Goals\Pages; +use Piwik\Report\ReportWidgetFactory; +use Piwik\Site; +use Piwik\Widget\WidgetsList; class Get extends Base { @@ -25,6 +38,104 @@ class Get extends Base $this->parameters = null; } + public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory) + { + $idSite = $this->getIdSite(); + $goals = API::getInstance()->getGoals($idSite); + $reports = Goals::getReportsWithGoalMetrics(); + + $page = new Pages($factory, $reports); + + $widgetsList->addWidgetConfigs($page->createGoalsOverviewPage($goals)); + + if ($this->isEcommerceEnabled($idSite)) { + $widgetsList->addWidgetConfigs($page->createEcommerceOverviewPage()); + $widgetsList->addWidgetConfigs($page->createEcommerceSalesPage()); + } + + foreach ($goals as $goal) { + $widgetsList->addWidgetConfigs($page->createGoalDetailPage($goal)); + } + } + + private function getIdSite() + { + return Common::getRequestVar('idSite', null, 'int'); + } + + private function isEcommerceEnabled($idSite) + { + if (!Plugin\Manager::getInstance()->isPluginActivated('Ecommerce')) { + return false; + } + + $site = new Site($idSite); + return $site->isEcommerceEnabled(); + } + + public function configureView(ViewDataTable $view) + { + if ($view->isViewDataTableId(Sparklines::ID)) { + /** @var Sparklines $view */ + $idSite = $this->getIdSite(); + $isEcommerceEnabled = $this->isEcommerceEnabled($idSite); + + $idGoal = Common::getRequestVar('idGoal', 0, 'int'); + + $formatter = new Formatter(); + $view->config->filters[] = function (DataTable $table) use ($formatter, $idSite) { + $firstRow = $table->getFirstRow(); + if ($firstRow) { + $revenue = $firstRow->getColumn('revenue'); + $firstRow->setColumn('revenue', $formatter->getPrettyMoney($revenue, $idSite)); + } + }; + + $view->config->addTranslations(array( + 'nb_visits' => Piwik::translate('VisitsSummary_NbVisitsDescription'), + 'nb_conversions' => Piwik::translate('Goals_ConversionsDescription'), + 'nb_visits_converted' => Piwik::translate('General_NVisits'), + 'conversion_rate' => Piwik::translate('Goals_OverallConversionRate'), + 'revenue' => Piwik::translate('Goals_OverallRevenue'), + )); + + $allowMultiple = Common::getRequestVar('allow_multiple', 0, 'int'); + + if ($allowMultiple) { + $view->config->addSparklineMetric(array('nb_conversions', 'nb_visits_converted'), $order = 10); + } else { + $view->config->addSparklineMetric(array('nb_conversions'), $order = 10); + } + + $view->config->addSparklineMetric(array('conversion_rate'), $order = 20); + + if (empty($idGoal)) { + // goals overview sparklines below evolution graph + + if ($isEcommerceEnabled) { + // this would be ideally done in Ecommerce plugin but then it is hard to keep same order + $view->config->addSparklineMetric(array('revenue'), $order = 30); + } + + } else { + $onlySummary = Common::getRequestVar('only_summary', 0, 'int'); + + if ($onlySummary) { + // in Goals Overview we list an overview for each goal.... + $view->config->addTranslation('conversion_rate', Piwik::translate('Goals_ConversionRate')); + + } elseif ($isEcommerceEnabled) { + // in Goals detail page... + $view->config->addSparklineMetric(array('revenue'), $order = 30); + } + } + } else if ($view->isViewDataTableId(Evolution::ID)) { + if (empty($view->config->columns_to_display)) { + $view->config->columns_to_display = array('nb_conversions'); + } + } + } + public function configureReportMetadata(&$availableReports, $infos) { if (!$this->isEnabled()) { diff --git a/plugins/Goals/Widgets.php b/plugins/Goals/Widgets.php deleted file mode 100644 index 94d91bda5c..0000000000 --- a/plugins/Goals/Widgets.php +++ /dev/null @@ -1,39 +0,0 @@ -addWidget('Goals_GoalsOverview', 'widgetGoalsOverview'); - - $idSite = $this->getIdSite(); - $goals = API::getInstance()->getGoals($idSite); - - if (count($goals) > 0) { - foreach ($goals as $goal) { - $name = Common::sanitizeInputValue($goal['name']); - $params = array('idGoal' => $goal['idgoal']); - - $this->addWidget($name, 'widgetGoalReport', $params); - } - } - } - - private function getIdSite() - { - return Common::getRequestVar('idSite', null, 'int'); - } - -} diff --git a/plugins/Goals/Widgets/AddNewGoal.php b/plugins/Goals/Widgets/AddNewGoal.php new file mode 100644 index 0000000000..b692309b9d --- /dev/null +++ b/plugins/Goals/Widgets/AddNewGoal.php @@ -0,0 +1,38 @@ +getGoals($idSite); + + $config->setCategoryId('Goals_Goals'); + $config->setSubcategoryId('Goals_AddNewGoal'); + $config->setParameters(array('idGoal' => '')); + $config->setIsNotWidgetizable(); + + if (Piwik::isUserHasAdminAccess($idSite)) { + $config->setName('Goals_AddNewGoal'); + } else { + $config->setName('Goals_CreateNewGOal'); + } + + if (count($goals) !== 0) { + $config->disable(); + } + } +} diff --git a/plugins/Goals/Widgets/EditGoals.php b/plugins/Goals/Widgets/EditGoals.php new file mode 100644 index 0000000000..d0bb52667c --- /dev/null +++ b/plugins/Goals/Widgets/EditGoals.php @@ -0,0 +1,37 @@ +getGoals($idSite); + + $config->setCategoryId('Goals_Goals'); + $config->setSubcategoryId('Goals_ManageGoals'); + $config->setIsNotWidgetizable(); + + if (Piwik::isUserHasAdminAccess($idSite)) { + $config->setName('Goals_ManageGoals'); + } else { + $config->setName('Goals_CreateNewGOal'); + } + + if (count($goals) === 0) { + $config->disable(); + } + } +} diff --git a/plugins/Goals/lang/en.json b/plugins/Goals/lang/en.json index 0545d0640f..8820b333e7 100644 --- a/plugins/Goals/lang/en.json +++ b/plugins/Goals/lang/en.json @@ -36,6 +36,7 @@ "ConversionByTypeReportDocumentation": "This report provides detailed information about the goal performance (conversions, conversion rates and revenue per visit) for each of the categories available in the left panel. %s Please click on one of the categories to view the report. %s For more information, read the %sTracking Goals documentation%s", "ConversionRate": "%s conversion rate", "Conversions": "%s conversions", + "ConversionsDescription": "conversions", "ConversionsOverview": "Conversions Overview", "ConversionsOverviewBy": "Conversions overview by type of visit", "DaysToConv": "Days to Conversion", @@ -79,8 +80,8 @@ "NoGoalsNeedAccess": "Only an Administrator or a user with Super User access can manage Goals for a given website. Please ask your Piwik administrator to set up a Goal for your website.
    Tracking Goals is a great way to help understand and maximize your website performance!", "NeedAccess": "Only an Administrator or a user with Super User access can manage Goals for a given website.", "Optional": "(optional)", - "OverallConversionRate": "%s overall conversion rate (visits with a completed goal)", - "OverallRevenue": "%s overall revenue", + "OverallConversionRate": "overall conversion rate (visits with a completed goal)", + "OverallRevenue": "overall revenue", "PageTitle": "Page Title", "Pattern": "Pattern", "PluginDescription": "Create Goals and see detailed reports about your goal conversions: evolution over time, revenue per visit, conversions per referrer, per keyword, and more.", diff --git a/plugins/Goals/templates/_titleAndEvolutionGraph.twig b/plugins/Goals/templates/_titleAndEvolutionGraph.twig deleted file mode 100644 index 0a2fdc1e31..0000000000 --- a/plugins/Goals/templates/_titleAndEvolutionGraph.twig +++ /dev/null @@ -1,86 +0,0 @@ - - -{% if displayFullReport or headline is defined %} -

    {% if headline is defined %}{{ headline }}{% elseif goalName is defined %}{{ 'Goals_GoalX'|translate(goalName) }}{% else %}{{ 'General_EvolutionOverPeriod'|translate }}{% endif %}

    -{% endif %} -{{ graphEvolution|raw }} - -
    -
    {{ sparkline(urlSparklineConversions) }} - {% if ecommerce is defined %} - {{ nb_conversions }} - {{ 'General_EcommerceOrders'|translate }} - - {% else %} - {{ 'Goals_Conversions'|translate(""~nb_conversions~"")|raw }} - {% endif %} - {% if goalAllowMultipleConversionsPerVisit is defined and goalAllowMultipleConversionsPerVisit %} - ({{ 'General_NVisits'|translate(""~nb_visits_converted~"")|raw }}) - {% endif %} -
    - {% if revenue != 0 or ecommerce is defined %} -
    - {{ sparkline(urlSparklineRevenue) }} - {% set revenue=revenue|money(idSite) %} - {% if ecommerce is defined %} - {{ revenue|raw }} {{ 'General_TotalRevenue'|translate }} - {% else %} - {{ 'Goals_OverallRevenue'|translate(""~revenue~"")|raw }} - {% endif %} -
    - {% endif %} - {% if ecommerce is defined %} -
    {{ sparkline(urlSparklineAverageOrderValue) }} - {{ avg_order_revenue|money(idSite)|raw }} - {{ 'General_AverageOrderValue'|translate }} -
    - {% endif %} - -
    -
    -
    {{ sparkline(urlSparklineConversionRate) }} - {% if ecommerce is defined %} - {% set ecommerceOrdersText %}{{ 'General_EcommerceOrders'|translate }}{% endset %} - {{ 'Goals_ConversionRate'|translate(""~conversion_rate~" "~ecommerceOrdersText)|raw }} - {% else %} - {{ 'Goals_OverallConversionRate'|translate(""~conversion_rate~"")|raw }} - {% endif %} -
    - {% if ecommerce is defined %} -
    {{ sparkline(urlSparklinePurchasedProducts) }} - {{ items }} {{ 'General_PurchasedProducts'|translate }}
    - {% endif %} -
    -{% if ecommerce is defined %} -
    -
    - {{ 'General_AbandonedCarts'|translate }} -
    - -
    - {{ sparkline(cart_urlSparklineConversions) }} - {% set ecommerceAbandonedCartsText %}{{ 'Goals_AbandonedCart'|translate }}{% endset %} - {{ cart_nb_conversions }} {{ 'General_VisitsWith'|translate(ecommerceAbandonedCartsText) }} -
    - -
    - {{ sparkline(cart_urlSparklineRevenue) }} - {% set revenue %}{{ cart_revenue|money(idSite)|raw }}{% endset %} - {% set revenueText %}{{ 'General_ColumnRevenue'|translate }}{% endset %} - {{ revenue }} {{ 'Goals_LeftInCart'|translate(revenueText) }} -
    - -
    - {{ sparkline(cart_urlSparklineConversionRate) }} - {{ cart_conversion_rate }} - {{ 'General_VisitsWith'|translate(ecommerceAbandonedCartsText) }} -
    -
    -{% endif %} -{% include "_sparklineFooter.twig" %} - diff --git a/plugins/Goals/templates/addNewGoal.twig b/plugins/Goals/templates/addNewGoal.twig index a2b44b88e9..844892ecbc 100644 --- a/plugins/Goals/templates/addNewGoal.twig +++ b/plugins/Goals/templates/addNewGoal.twig @@ -1,5 +1,4 @@ {% if userCanEditGoals %} -

    {{ 'Goals_AddNewGoal'|translate }}

    {{ 'Goals_NewGoalIntro'|translate }}

    {{ 'Goals_LearnMoreAboutGoalTrackingDocumentation'|translate("","")|raw }} {{ 'Goals_ManageGoalsOrCreateANewGoal'|translate("","")|raw }} diff --git a/plugins/Goals/templates/conversionOverview.twig b/plugins/Goals/templates/conversionOverview.twig new file mode 100644 index 0000000000..2697527eb7 --- /dev/null +++ b/plugins/Goals/templates/conversionOverview.twig @@ -0,0 +1,15 @@ +

      + {% if topDimensions.country is defined %} +
    • {{ 'Goals_BestCountries'|translate }} {% include '@Goals/_listTopDimension.twig' with {'topDimension':topDimensions.country} %}
    • + {% endif %} + {% if topDimensions.keyword is defined and topDimensions.keyword|length > 0 %} +
    • {{ 'Goals_BestKeywords'|translate }} {% include '@Goals/_listTopDimension.twig' with {'topDimension':topDimensions.keyword} %}
    • + {% endif %} + {% if topDimensions.website is defined and topDimensions.website|length > 0 %} +
    • {{ 'Goals_BestReferrers'|translate }} {% include '@Goals/_listTopDimension.twig' with {'topDimension':topDimensions.website} %}
    • + {% endif %} +
    • + {{ 'Goals_ReturningVisitorsConversionRateIs'|translate(""~conversion_rate_returning~"")|raw }} + , {{ 'Goals_NewVisitorsConversionRateIs'|translate(""~conversion_rate_new~"")|raw }} +
    • +

    \ No newline at end of file diff --git a/plugins/Goals/templates/editGoals.twig b/plugins/Goals/templates/editGoals.twig index 76b64b9918..1bc8956511 100644 --- a/plugins/Goals/templates/editGoals.twig +++ b/plugins/Goals/templates/editGoals.twig @@ -1,7 +1,5 @@ {% if userCanEditGoals %} -

    {{ 'Goals_ManageGoals'|translate }}

    - {% include "@Goals/_addEditGoal.twig" %} {% else %} diff --git a/plugins/Goals/templates/getGoalReportView.twig b/plugins/Goals/templates/getGoalReportView.twig deleted file mode 100644 index 2cb3b7f4d0..0000000000 --- a/plugins/Goals/templates/getGoalReportView.twig +++ /dev/null @@ -1,66 +0,0 @@ - -{% include "@Goals/_titleAndEvolutionGraph.twig" | raw %} - -
    -{% if nb_conversions > 0 %} -

    {{ 'Goals_ConversionsOverview'|translate }}

    -
      - {% if ecommerce is not defined %} - {% if topDimensions.country is defined %} -
    • {{ 'Goals_BestCountries'|translate }} {% include '@Goals/_listTopDimension.twig' with {'topDimension':topDimensions.country} %}
    • - {% endif %} - {% if topDimensions.keyword is defined and topDimensions.keyword|length > 0 %} -
    • {{ 'Goals_BestKeywords'|translate }} {% include '@Goals/_listTopDimension.twig' with {'topDimension':topDimensions.keyword} %}
    • - {% endif %} - {% if topDimensions.website is defined and topDimensions.website|length > 0 %} -
    • {{ 'Goals_BestReferrers'|translate }} {% include '@Goals/_listTopDimension.twig' with {'topDimension':topDimensions.website} %}
    • - {% endif %} -
    • - {{ 'Goals_ReturningVisitorsConversionRateIs'|translate(""~conversion_rate_returning~"")|raw }} - , {{ 'Goals_NewVisitorsConversionRateIs'|translate(""~conversion_rate_new~"")|raw }} -
    • - {% else %} -
    • - {{ 'General_ColumnRevenue'|translate }}: {{ revenue|money(idSite)|raw -}} - {% if revenue_subtotal is not empty %}, - {{ 'General_Subtotal'|translate }}: {{ revenue_subtotal|money(idSite)|raw -}} - {% endif %} - {%- if revenue_tax is not empty -%}, - {{ 'General_Tax'|translate }}: {{ revenue_tax|money(idSite)|raw -}} - {% endif %} - {%- if revenue_shipping is not empty -%}, - {{ 'General_Shipping'|translate }}: {{ revenue_shipping|money(idSite)|raw -}} - {% endif %} - {%- if revenue_discount is not empty -%}, - {{ 'General_Discount'|translate }}: {{ revenue_discount|money(idSite)|raw -}} - {% endif %} -
    • - {% endif %} -
    -{% endif %} - - - -{% if displayFullReport %} - {% if nb_conversions > 0 or cart_nb_conversions is defined %} -

    - {% if idGoal is defined %} - {{ 'Goals_GoalConversionsBy'|translate(goalName) }} - {% else %} - {{ 'Goals_ConversionsOverviewBy'|translate }} - {% endif %} -

    - {{ goalReportsByDimension|raw }} - {% endif %} -{% endif %} diff --git a/plugins/Goals/templates/getOverviewView.twig b/plugins/Goals/templates/getOverviewView.twig deleted file mode 100644 index 909fd01711..0000000000 --- a/plugins/Goals/templates/getOverviewView.twig +++ /dev/null @@ -1,58 +0,0 @@ - - -{% include "@Goals/_titleAndEvolutionGraph.twig" %} -{% set sum_nb_conversions=nb_conversions %} - -{% for goal in goalMetrics %} - {% set nb_conversions=goal.nb_conversions %} - {% set nb_visits_converted=goal.nb_visits_converted %} - {% set conversion_rate=goal.conversion_rate %} - {% set name=goal.name %} -
    -

    - - {{ 'Goals_GoalX'|translate("'"~name~"'") }} - -

    - - {% if not isWidget %} -
    -
    - {% endif %} - -
    {{ sparkline(goal.urlSparklineConversions) }} - {{ 'Goals_Conversions'|translate(""~nb_conversions~"")|raw }} - {% if goal.goalAllowMultipleConversionsPerVisit %} - ({{ 'General_NVisits'|translate(""~nb_visits_converted~"") | raw }}) - {% endif %} -
    - - {% if not isWidget %} -
    -
    - {% endif %} - -
    {{ sparkline(goal.urlSparklineConversionRate) }} - {{ 'Goals_ConversionRate'|translate(""~conversion_rate~"")|raw }} -
    - - {% if not isWidget %} -
    -
    - {% endif %} - -
    -{% endfor %} - -{% if displayFullReport %} - {% if sum_nb_conversions != 0 %} -

    - {% if idGoal is defined %} - {{ 'Goals_GoalConversionsBy'|translate(goalName) }} - {% else %} - {{ 'Goals_ConversionsOverviewBy'|translate }} - {% endif %} -

    - {{ goalReportsByDimension|raw }} - {% endif %} -{% endif %} diff --git a/plugins/Insights/Widgets.php b/plugins/Insights/Widgets.php deleted file mode 100644 index 799662deb5..0000000000 --- a/plugins/Insights/Widgets.php +++ /dev/null @@ -1,20 +0,0 @@ -addWidget('Insights_OverviewWidgetTitle', 'getInsightsOverview'); - $this->addWidget('Insights_MoversAndShakersWidgetTitle', 'getOverallMoversAndShakers'); - } -} diff --git a/plugins/Insights/Widgets/GetInsightsOverview.php b/plugins/Insights/Widgets/GetInsightsOverview.php new file mode 100644 index 0000000000..e715865a41 --- /dev/null +++ b/plugins/Insights/Widgets/GetInsightsOverview.php @@ -0,0 +1,20 @@ +setCategoryId('Insights_WidgetCategory'); + $config->setName('Insights_OverviewWidgetTitle'); + } +} diff --git a/plugins/Insights/Widgets/GetOverallMoversAndShakers.php b/plugins/Insights/Widgets/GetOverallMoversAndShakers.php new file mode 100644 index 0000000000..e175e76519 --- /dev/null +++ b/plugins/Insights/Widgets/GetOverallMoversAndShakers.php @@ -0,0 +1,20 @@ +setCategoryId('Insights_WidgetCategory'); + $config->setName('Insights_MoversAndShakersWidgetTitle'); + } +} diff --git a/plugins/Live/Categories/LiveCategory.php b/plugins/Live/Categories/LiveCategory.php new file mode 100644 index 0000000000..c3b1a52c91 --- /dev/null +++ b/plugins/Live/Categories/LiveCategory.php @@ -0,0 +1,17 @@ +category = 'Live!'; + $this->categoryId = 'Live!'; } public function configureReportMetadata(&$availableReports, $infos) diff --git a/plugins/Live/Reports/GetLastVisitsDetails.php b/plugins/Live/Reports/GetLastVisitsDetails.php index 8cf2268d28..f714989b75 100644 --- a/plugins/Live/Reports/GetLastVisitsDetails.php +++ b/plugins/Live/Reports/GetLastVisitsDetails.php @@ -8,10 +8,10 @@ */ namespace Piwik\Plugins\Live\Reports; -use Piwik\Menu\MenuReporting; use Piwik\Plugin\Report; use Piwik\Plugins\Live\Visualizations\VisitorLog; -use Piwik\WidgetsList; +use Piwik\Report\ReportWidgetFactory; +use Piwik\Widget\WidgetsList; class GetLastVisitsDetails extends Base { @@ -20,8 +20,9 @@ class GetLastVisitsDetails extends Base protected function init() { parent::init(); - $this->widgetTitle = 'Live_VisitorLog'; $this->order = 2; + $this->categoryId = 'General_Visitors'; + $this->subcategoryId = 'Live_VisitorLog'; } public function getDefaultTypeViewDataTable() @@ -34,17 +35,14 @@ class GetLastVisitsDetails extends Base return true; } - public function configureReportingMenu(MenuReporting $menu) + public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory) { - if ($this->isEnabled()) { - $url = array('module' => $this->module, 'action' => 'indexVisitorLog'); - $menu->addVisitorsItem($this->widgetTitle, $url, $order = 5); - } - } - - public function configureWidget(WidgetsList $widget) - { - $widget->add($this->category, $this->widgetTitle, $this->module, 'getVisitorLog', array('small' => 1)); + $widget = $factory->createWidget() + ->forceViewDataTable(VisitorLog::ID) + ->setName('Live_VisitorLog') + ->setOrder(10) + ->setParameters(array('small' => 1)); + $widgetsList->addWidgetConfig($widget); } } diff --git a/plugins/Live/Reports/GetSimpleLastVisitCount.php b/plugins/Live/Reports/GetSimpleLastVisitCount.php index 9b0db30769..d2f535ff4e 100644 --- a/plugins/Live/Reports/GetSimpleLastVisitCount.php +++ b/plugins/Live/Reports/GetSimpleLastVisitCount.php @@ -14,17 +14,24 @@ use Piwik\Piwik; use Piwik\Plugin\Report; use Piwik\Plugins\Live\Controller; use Piwik\API\Request; +use Piwik\Report\ReportWidgetFactory; use Piwik\View; +use Piwik\Widget\WidgetsList; class GetSimpleLastVisitCount extends Base { protected function init() { parent::init(); - $this->widgetTitle = 'Live_RealTimeVisitorCount'; $this->order = 3; } + public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory) + { + $widget = $factory->createWidget()->setName('Live_RealTimeVisitorCount')->setOrder(15); + $widgetsList->addWidgetConfig($widget); + } + public function render() { $lastMinutes = Config::getInstance()->General[Controller::SIMPLE_VISIT_COUNT_WIDGET_LAST_MINUTES_CONFIG_KEY]; diff --git a/plugins/Live/Widgets.php b/plugins/Live/Widgets.php deleted file mode 100644 index c4c96c53e9..0000000000 --- a/plugins/Live/Widgets.php +++ /dev/null @@ -1,27 +0,0 @@ -addWidget('Live_VisitorsInRealTime', 'widget'); - - // the visitor profile uses a segment that is not accessible to the anonymous user, so don't bother showing this widget - if (!Piwik::isUserIsAnonymous()) { - $this->addWidget('Live_VisitorProfile', 'getVisitorProfilePopup'); - } - } - -} diff --git a/plugins/Live/Widgets/GetVisitorProfilePopup.php b/plugins/Live/Widgets/GetVisitorProfilePopup.php new file mode 100644 index 0000000000..0d01a7abca --- /dev/null +++ b/plugins/Live/Widgets/GetVisitorProfilePopup.php @@ -0,0 +1,33 @@ +setCategoryId('General_Visitors'); + $config->setName('Live_VisitorProfile'); + $config->setOrder(25); + + if (Piwik::isUserIsAnonymous()) { + $config->disable(); + } + } + + public function render() + { + + } + +} diff --git a/plugins/Live/Widgets/Widget.php b/plugins/Live/Widgets/Widget.php new file mode 100644 index 0000000000..e058423b66 --- /dev/null +++ b/plugins/Live/Widgets/Widget.php @@ -0,0 +1,21 @@ +setCategoryId('Live!'); + $config->setName('Live_VisitorsInRealTime'); + $config->setOrder(20); + } +} diff --git a/plugins/Live/templates/index.twig b/plugins/Live/templates/index.twig index ced0699bb9..b0a9382b65 100644 --- a/plugins/Live/templates/index.twig +++ b/plugins/Live/templates/index.twig @@ -43,7 +43,7 @@ {% if not disableLink %}   - {{ 'Live_LinkVisitorLog'|translate }} + {{ 'Live_LinkVisitorLog'|translate }} {% endif %}
    {% endspaceless %} diff --git a/plugins/Morpheus/javascripts/piwikHelper.js b/plugins/Morpheus/javascripts/piwikHelper.js index 163ea90160..cc6ae5dde5 100644 --- a/plugins/Morpheus/javascripts/piwikHelper.js +++ b/plugins/Morpheus/javascripts/piwikHelper.js @@ -125,6 +125,10 @@ var piwikHelper = { compileAngularComponents: function (selector) { var $element = $(selector); + if (!$element || !$element.length) { + return; + } + angular.element(document).injector().invoke(function($compile) { var scope = angular.element($element).scope(); $compile($element)(scope); @@ -155,9 +159,9 @@ var piwikHelper = { var button = {text: text}; if(typeof handles[role] == 'function') { - button.click = function(){$(this).dialog("close"); handles[role].apply()}; + button.click = function(){ $(this).dialog("close"); handles[role].apply()}; } else { - button.click = function(){$(this).dialog("close");}; + button.click = function(){ $(this).dialog("close");}; } if (title) { diff --git a/plugins/Morpheus/stylesheets/ui/_map.less b/plugins/Morpheus/stylesheets/ui/_map.less index 0446610c2d..731f4e369b 100644 --- a/plugins/Morpheus/stylesheets/ui/_map.less +++ b/plugins/Morpheus/stylesheets/ui/_map.less @@ -56,6 +56,10 @@ font-size: 14px; } +.uiTest .realTimeMap_datetime { + visibility: hidden; +} + .realtime-map[data-name=white-fill] { color: #f2f2f2 !important; } diff --git a/plugins/Morpheus/templates/layout.twig b/plugins/Morpheus/templates/layout.twig index 1e9f1f0d5c..87cb863356 100644 --- a/plugins/Morpheus/templates/layout.twig +++ b/plugins/Morpheus/templates/layout.twig @@ -47,6 +47,8 @@ {% endblock %}
    +
    + {% endblock %} diff --git a/plugins/MultiSites/Categories/MultiSitesCategory.php b/plugins/MultiSites/Categories/MultiSitesCategory.php new file mode 100644 index 0000000000..0e884d3cfb --- /dev/null +++ b/plugins/MultiSites/Categories/MultiSitesCategory.php @@ -0,0 +1,17 @@ +category = 'General_MultiSitesSummary'; + $this->categoryId = 'General_MultiSitesSummary'; $allMetricsInfo = API::getApiMetrics($enhanced = true); diff --git a/plugins/Provider/Reports/GetProvider.php b/plugins/Provider/Reports/GetProvider.php index e7cfcfa753..adf03cd26f 100644 --- a/plugins/Provider/Reports/GetProvider.php +++ b/plugins/Provider/Reports/GetProvider.php @@ -13,17 +13,26 @@ use Piwik\Piwik; use Piwik\Plugin\Report; use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\Provider\Columns\Provider; +use Piwik\Report\ReportWidgetFactory; +use Piwik\Widget\WidgetsList; class GetProvider extends Report { protected function init() { - $this->category = 'General_Visitors'; + $this->categoryId = 'General_Visitors'; $this->dimension = new Provider(); $this->name = Piwik::translate('Provider_ColumnProvider'); $this->documentation = Piwik::translate('Provider_ProviderReportDocumentation', '
    '); $this->order = 50; - $this->widgetTitle = 'Provider_WidgetProviders'; + + $this->subcategoryId = 'UserCountry_SubmenuLocations'; + } + + public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory) + { + $widget = $factory->createWidget()->setName('Provider_WidgetProviders'); + $widgetsList->addWidgetConfig($widget); } public function configureView(ViewDataTable $view) diff --git a/plugins/Referrers/Categories/AllReferrersSubcategory.php b/plugins/Referrers/Categories/AllReferrersSubcategory.php new file mode 100644 index 0000000000..277fc762dd --- /dev/null +++ b/plugins/Referrers/Categories/AllReferrersSubcategory.php @@ -0,0 +1,19 @@ +graphEvolutionReferrers = $this->getEvolutionGraph(Common::REFERRER_TYPE_DIRECT_ENTRY, array(), array('nb_visits')); - $view->nameGraphEvolutionReferrers = 'Referrers.getEvolutionGraph'; - - $nameValues = $this->getReferrersVisitorsByType(); + $metrics = $this->getReferrersVisitorsByType(); + $distinctMetrics = $this->getDistinctReferrersMetrics(); - $totalVisits = array_sum($nameValues); - foreach ($nameValues as $name => $value) { - $view->$name = $value; + $totalVisits = array_sum($metrics); + foreach ($metrics as $name => $value) { // calculate percent of total, if there were any visits - if ($value != 0 - && $totalVisits != 0 - ) { + if ($value != 0 && $totalVisits != 0) { $percentName = $name . 'Percent'; - $view->$percentName = round(($value / $totalVisits) * 100, 0); + $metrics[$percentName] = round(($value / $totalVisits) * 100, 0); } } - // set distinct metrics - $distinctMetrics = $this->getDistinctReferrersMetrics(); - foreach ($distinctMetrics as $name => $value) { - $view->$name = $value; - } - // calculate evolution for visit metrics & distinct metrics list($lastPeriodDate, $ignore) = Range::getLastDate(); if ($lastPeriodDate !== false) { @@ -74,71 +64,109 @@ class Controller extends \Piwik\Plugin\Controller // visit metrics $previousValues = $this->getReferrersVisitorsByType($lastPeriodDate); - $this->addEvolutionPropertiesToView($view, $prettyDate, $nameValues, $prettyLastPeriodDate, $previousValues); + $metrics = $this->addEvolutionPropertiesToView($prettyDate, $metrics, $prettyLastPeriodDate, $previousValues); // distinct metrics $previousValues = $this->getDistinctReferrersMetrics($lastPeriodDate); - $this->addEvolutionPropertiesToView($view, $prettyDate, $distinctMetrics, $prettyLastPeriodDate, $previousValues); + $distinctMetrics = $this->addEvolutionPropertiesToView($prettyDate, $distinctMetrics, $prettyLastPeriodDate, $previousValues); } - // sparkline for the historical data of the above values - $view->urlSparklineSearchEngines = $this->getReferrerUrlSparkline(Common::REFERRER_TYPE_SEARCH_ENGINE); - $view->urlSparklineDirectEntry = $this->getReferrerUrlSparkline(Common::REFERRER_TYPE_DIRECT_ENTRY); - $view->urlSparklineWebsites = $this->getReferrerUrlSparkline(Common::REFERRER_TYPE_WEBSITE); - $view->urlSparklineCampaigns = $this->getReferrerUrlSparkline(Common::REFERRER_TYPE_CAMPAIGN); - // sparklines for the evolution of the distinct keywords count/websites count/ etc - $view->urlSparklineDistinctSearchEngines = $this->getUrlSparkline('getLastDistinctSearchEnginesGraph'); - $view->urlSparklineDistinctKeywords = $this->getUrlSparkline('getLastDistinctKeywordsGraph'); - $view->urlSparklineDistinctWebsites = $this->getUrlSparkline('getLastDistinctWebsitesGraph'); - $view->urlSparklineDistinctCampaigns = $this->getUrlSparkline('getLastDistinctCampaignsGraph'); + /** @var Sparklines $view */ + $view = ViewDataTable\Factory::build(Sparklines::ID, $api = false, $controller = false, $force = true, $loadUserParams = false); - return $view->render(); - } + // DIRECT ENTRY + $values = array($metrics['visitorsFromDirectEntry']); + $descriptions = array(Piwik::translate('Referrers_TypeDirectEntries')); - public function allReferrers() - { - $view = new View('@Referrers/allReferrers'); + if (!empty($metrics['visitorsFromDirectEntryPercent'])) { + $values[] = $metrics['visitorsFromDirectEntryPercent']; + $descriptions[] = Piwik::translate('Referrers_XPercentOfVisits'); + } - // building the referrers summary report - $view->dataTableReferrerType = $this->renderReport('getReferrerType'); + $directEntryParams = $this->getReferrerSparklineParams(Common::REFERRER_TYPE_DIRECT_ENTRY); - $nameValues = $this->getReferrersVisitorsByType(); + $view->config->addSparkline($directEntryParams, $values, $descriptions, @$metrics['visitorsFromDirectEntryEvolution']); - $totalVisits = array_sum($nameValues); - foreach ($nameValues as $name => $value) { - $view->$name = $value; - // calculate percent of total, if there were any visits - if ($value != 0 - && $totalVisits != 0 - ) { - $percentName = $name . 'Percent'; - $view->$percentName = round(($value / $totalVisits) * 100, 0); - } + // WEBSITES + $values = array($metrics['visitorsFromWebsites']); + $descriptions = array(Piwik::translate('Referrers_TypeWebsites')); + + if (!empty($metrics['visitorsFromWebsitesPercent'])) { + $values[] = $metrics['visitorsFromWebsitesPercent']; + $descriptions[] = Piwik::translate('Referrers_XPercentOfVisits'); } - $view->totalVisits = $totalVisits; - $view->referrersReportsByDimension = $this->renderReport('getAll'); + $searchEngineParams = $this->getReferrerSparklineParams(Common::REFERRER_TYPE_WEBSITE); - return $view->render(); - } + $view->config->addSparkline($searchEngineParams, $values, $descriptions, @$metrics['visitorsFromWebsitesEvolution']); + + + // SEARCH ENGINES + $values = array($metrics['visitorsFromSearchEngines']); + $descriptions = array(Piwik::translate('Referrers_TypeSearchEngines')); + + if (!empty($metrics['visitorsFromSearchEnginesPercent'])) { + $values[] = $metrics['visitorsFromSearchEnginesPercent']; + $descriptions[] = Piwik::translate('Referrers_XPercentOfVisits'); + } + $searchEngineParams = $this->getReferrerSparklineParams(Common::REFERRER_TYPE_SEARCH_ENGINE); + + $view->config->addSparkline($searchEngineParams, $values, $descriptions, @$metrics['visitorsFromSearchEnginesEvolution']); + + + // CAMPAIGNS + $values = array($metrics['visitorsFromCampaigns']); + $descriptions = array(Piwik::translate('Referrers_TypeCampaigns')); + + if (!empty($metrics['visitorsFromCampaignsPercent'])) { + $values[] = $metrics['visitorsFromCampaignsPercent']; + $descriptions[] = Piwik::translate('Referrers_XPercentOfVisits'); + } + + $searchEngineParams = $this->getReferrerSparklineParams(Common::REFERRER_TYPE_CAMPAIGN); + + $view->config->addSparkline($searchEngineParams, $values, $descriptions, @$metrics['visitorsFromCampaignsEvolution']); + + + // DISTINCT SEARCH ENGINES + $sparklineParams = $this->getDistinctSparklineUrlParams('getLastDistinctSearchEnginesGraph'); + $value = $distinctMetrics['numberDistinctSearchEngines']; + $description = Piwik::translate('Referrers_DistinctSearchEngines'); + + $view->config->addSparkline($sparklineParams, $value, $description, @$distinctMetrics['numberDistinctSearchEnginesEvolution']); + + + // DISTINCT WEBSITES + $sparklineParams = $this->getDistinctSparklineUrlParams('getLastDistinctWebsitesGraph'); + $values = array($distinctMetrics['numberDistinctWebsites'], $distinctMetrics['numberDistinctWebsitesUrls']); + $descriptions = array(Piwik::translate('Referrers_DistinctWebsites'), Piwik::translate('Referrers_UsingNDistinctUrls')); + + $view->config->addSparkline($sparklineParams, $values, $descriptions, @$distinctMetrics['numberDistinctWebsitesEvolution']); + + + // DISTINCT KEYWORDS + $sparklineParams = $this->getDistinctSparklineUrlParams('getLastDistinctKeywordsGraph'); + $value = $distinctMetrics['numberDistinctKeywords']; + $description = Piwik::translate('Referrers_DistinctKeywords'); + + $view->config->addSparkline($sparklineParams, $value, $description, @$distinctMetrics['numberDistinctKeywordsEvolution']); + + + // DISTINCT CAMPAIGNS + $sparklineParams = $this->getDistinctSparklineUrlParams('getLastDistinctCampaignsGraph'); + $value = $distinctMetrics['numberDistinctCampaigns']; + $description = Piwik::translate('Referrers_DistinctCampaigns'); + + $view->config->addSparkline($sparklineParams, $value, $description, @$distinctMetrics['numberDistinctCampaignsEvolution']); - public function getSearchEnginesAndKeywords() - { - $view = new View('@Referrers/getSearchEnginesAndKeywords'); - $view->searchEngines = $this->renderReport('getSearchEngines'); - $view->keywords = $this->renderReport('getKeywords'); return $view->render(); } - public function indexWebsites() + private function getDistinctSparklineUrlParams($action) { - $view = new View('@Referrers/indexWebsites'); - $view->websites = $this->renderReport('getWebsites'); - $view->socials = $this->renderReport('getSocials'); - - return $view->render(); + return array('module' => $this->pluginName, 'action' => $action); } protected function getReferrersVisitorsByType($date = false) @@ -221,7 +249,7 @@ class Controller extends \Piwik\Plugin\Controller } else { // use $typeReferrer as default if ($typeReferrer === false) { - $typeReferrer = Common::getRequestVar('typeReferrer', false); + $typeReferrer = Common::getRequestVar('typeReferrer', Common::REFERRER_TYPE_DIRECT_ENTRY); } $label = self::getTranslatedReferrerTypeLabel($typeReferrer); $total = $this->translator->translate('General_Total'); @@ -416,14 +444,16 @@ function DisplayTopKeywords($url = "") * @param int $referrerType The referrer type. Referrer types are defined in Common class. * @return string The URL that can be used to get a sparkline image. */ - private function getReferrerUrlSparkline($referrerType) + private function getReferrerSparklineParams($referrerType) { $totalRow = $this->translator->translate('General_Total'); - return $this->getUrlSparkline( - 'getEvolutionGraph', - array('columns' => array('nb_visits'), - 'rows' => array(self::getTranslatedReferrerTypeLabel($referrerType), $totalRow), - 'typeReferrer' => $referrerType) + + return array( + 'columns' => array('nb_visits'), + 'rows' => array(self::getTranslatedReferrerTypeLabel($referrerType), $totalRow), + 'typeReferrer' => $referrerType, + 'module' => $this->pluginName, + 'action' => 'getReferrerType' ); } @@ -456,20 +486,32 @@ function DisplayTopKeywords($url = "") * Utility method that calculates evolution values for a set of current & past values * and sets properties on a View w/ HTML that displays the evolution percents. * - * @param View $view The view to set properties on. * @param string $date The date of the current values. * @param array $currentValues Array mapping view property names w/ present values. * @param string $lastPeriodDate The date of the period in the past. * @param array $previousValues Array mapping view property names w/ past values. Keys * in this array should be the same as keys in $currentValues. + * @return array Added current values */ - private function addEvolutionPropertiesToView($view, $date, $currentValues, $lastPeriodDate, $previousValues) + private function addEvolutionPropertiesToView($date, $currentValues, $lastPeriodDate, $previousValues) { foreach ($previousValues as $name => $pastValue) { $currentValue = $currentValues[$name]; $evolutionName = $name . 'Evolution'; - $view->$evolutionName = $this->getEvolutionHtml($date, $currentValue, $lastPeriodDate, $pastValue); + $currentValues[$evolutionName] = array( + 'currentValue' => $currentValue, + 'pastValue' => $pastValue, + 'tooltip' => Piwik::translate('General_EvolutionSummaryGeneric', array( + Piwik::translate('General_NVisits', $currentValue), + $date, + Piwik::translate('General_NVisits', $pastValue), + $lastPeriodDate, + CalculateEvolutionFilter::calculate($currentValue, $pastValue, $precision = 1) + )) + ); } + + return $currentValues; } } diff --git a/plugins/Referrers/Menu.php b/plugins/Referrers/Menu.php deleted file mode 100644 index cb92a43db3..0000000000 --- a/plugins/Referrers/Menu.php +++ /dev/null @@ -1,23 +0,0 @@ -addReferrersItem('', $this->urlForAction('index'), 20); - $menu->addReferrersItem('General_Overview', $this->urlForAction('index'), 1); - $menu->addReferrersItem('Referrers_WidgetGetAll', $this->urlForAction('allReferrers'), 2); - $menu->addReferrersItem('Referrers_SubmenuSearchEngines', $this->urlForAction('getSearchEnginesAndKeywords'), 3); - $menu->addReferrersItem('Referrers_SubmenuWebsites', $this->urlForAction('indexWebsites'), 4); - } -} diff --git a/plugins/Referrers/Reports/Base.php b/plugins/Referrers/Reports/Base.php index e4a6394c00..2bd240d191 100644 --- a/plugins/Referrers/Reports/Base.php +++ b/plugins/Referrers/Reports/Base.php @@ -12,7 +12,7 @@ abstract class Base extends \Piwik\Plugin\Report { protected function init() { - $this->category = 'Referrers_Referrers'; + $this->categoryId = 'Referrers_Referrers'; } } diff --git a/plugins/Referrers/Reports/GetAll.php b/plugins/Referrers/Reports/GetAll.php index 2079dd414d..cb5f17ee41 100644 --- a/plugins/Referrers/Reports/GetAll.php +++ b/plugins/Referrers/Reports/GetAll.php @@ -13,6 +13,8 @@ use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable; use Piwik\Plugins\Referrers\Columns\Referrer; use Piwik\Plugins\Referrers\Referrers; +use Piwik\Report\ReportWidgetFactory; +use Piwik\Widget\WidgetsList; class GetAll extends Base { @@ -23,7 +25,15 @@ class GetAll extends Base $this->name = Piwik::translate('Referrers_WidgetGetAll'); $this->documentation = Piwik::translate('Referrers_AllReferrersReportDocumentation', '
    '); $this->order = 2; - $this->widgetTitle = 'Referrers_WidgetGetAll'; + + $this->subcategoryId = 'Referrers_WidgetGetAll'; + } + + public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory) + { + $widgetsList->addWidgetConfig( + $factory->createWidget()->setName('Referrers_Referrers') + ); } public function getDefaultTypeViewDataTable() diff --git a/plugins/Referrers/Reports/GetCampaigns.php b/plugins/Referrers/Reports/GetCampaigns.php index a09affa70c..1d375423d8 100644 --- a/plugins/Referrers/Reports/GetCampaigns.php +++ b/plugins/Referrers/Reports/GetCampaigns.php @@ -24,8 +24,8 @@ class GetCampaigns extends Base $this->actionToLoadSubTables = 'getKeywordsFromCampaignId'; $this->hasGoalMetrics = true; $this->order = 9; - $this->widgetTitle = 'Referrers_Campaigns'; - $this->menuTitle = 'Referrers_Campaigns'; + + $this->subcategoryId = 'Referrers_Campaigns'; } public function configureView(ViewDataTable $view) diff --git a/plugins/Referrers/Reports/GetKeywords.php b/plugins/Referrers/Reports/GetKeywords.php index be8e8d3f4c..3239fefde0 100644 --- a/plugins/Referrers/Reports/GetKeywords.php +++ b/plugins/Referrers/Reports/GetKeywords.php @@ -11,7 +11,9 @@ namespace Piwik\Plugins\Referrers\Reports; use Piwik\Piwik; use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable; +use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Evolution; use Piwik\Plugins\Referrers\Columns\Keyword; +use Piwik\Tracker\Visit; class GetKeywords extends Base { @@ -24,7 +26,7 @@ class GetKeywords extends Base $this->actionToLoadSubTables = 'getSearchEnginesFromKeywordId'; $this->hasGoalMetrics = true; $this->order = 3; - $this->widgetTitle = 'Referrers_Keywords'; + $this->subcategoryId = 'Referrers_SubmenuSearchEngines'; } public function configureView(ViewDataTable $view) diff --git a/plugins/Referrers/Reports/GetReferrerType.php b/plugins/Referrers/Reports/GetReferrerType.php index f5656bfa7f..c09f8c6d17 100644 --- a/plugins/Referrers/Reports/GetReferrerType.php +++ b/plugins/Referrers/Reports/GetReferrerType.php @@ -12,7 +12,11 @@ use Piwik\Common; use Piwik\Piwik; use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable; +use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Evolution; +use Piwik\Plugins\CoreVisualizations\Visualizations\Sparklines; use Piwik\Plugins\Referrers\Columns\ReferrerType; +use Piwik\Widget\WidgetsList; +use Piwik\Report\ReportWidgetFactory; class GetReferrerType extends Base { @@ -32,7 +36,7 @@ class GetReferrerType extends Base $this->constantRowsCount = true; $this->hasGoalMetrics = true; $this->order = 1; - $this->widgetTitle = 'General_Overview'; + $this->subcategoryId = 'Referrers_WidgetGetAll'; } public function getDefaultTypeViewDataTable() @@ -40,6 +44,36 @@ class GetReferrerType extends Base return HtmlTable\AllColumns::ID; } + public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory) + { + $widgetsList->addWidgetConfig( + $factory->createWidget() + ->setName('Referrers_ReferrerTypes') + ->setSubcategoryId('Referrers_WidgetGetAll') + ); + + $widgetsList->addWidgetConfig( + $factory->createWidget() + ->setName('General_EvolutionOverPeriod') + ->setSubcategoryId('General_Overview') + ->setAction('getEvolutionGraph') + ->setIsNotWidgetizable() + ->forceViewDataTable(Evolution::ID) + ->addParameters(array( + 'columns' => $defaultColumns = array('nb_visits'), + )) + ); + + $widgetsList->addWidgetConfig( + $factory->createCustomWidget('getSparklines') + ->forceViewDataTable(Sparklines::ID) + ->setIsNotWidgetizable() + ->setName('Referrers_Type') + ->setSubcategoryId('General_Overview') + ->setOrder(10) + ); + } + public function configureView(ViewDataTable $view) { $idSubtable = Common::getRequestVar('idSubtable', false); diff --git a/plugins/Referrers/Reports/GetSearchEngines.php b/plugins/Referrers/Reports/GetSearchEngines.php index 3b66cd0784..0a17cd132e 100644 --- a/plugins/Referrers/Reports/GetSearchEngines.php +++ b/plugins/Referrers/Reports/GetSearchEngines.php @@ -24,7 +24,8 @@ class GetSearchEngines extends Base $this->actionToLoadSubTables = 'getKeywordsFromSearchEngineId'; $this->hasGoalMetrics = true; $this->order = 7; - $this->widgetTitle = 'Referrers_SearchEngines'; + + $this->subcategoryId = 'Referrers_SubmenuSearchEngines'; } public function configureView(ViewDataTable $view) diff --git a/plugins/Referrers/Reports/GetSocials.php b/plugins/Referrers/Reports/GetSocials.php index b49fac623a..7429ddd48f 100644 --- a/plugins/Referrers/Reports/GetSocials.php +++ b/plugins/Referrers/Reports/GetSocials.php @@ -14,6 +14,8 @@ use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable; use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Pie; use Piwik\Plugins\Referrers\Columns\SocialNetwork; +use Piwik\Report\ReportWidgetFactory; +use Piwik\Widget\WidgetsList; class GetSocials extends Base { @@ -25,7 +27,14 @@ class GetSocials extends Base $this->documentation = Piwik::translate('Referrers_WebsitesReportDocumentation', '
    '); $this->actionToLoadSubTables = 'getUrlsForSocial'; $this->order = 11; - $this->widgetTitle = 'Referrers_WidgetSocials'; + + $this->subcategoryId = 'Referrers_SubmenuWebsites'; + } + + public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory) + { + $widget = $factory->createWidget()->setName('Referrers_Socials'); + $widgetsList->addWidgetConfig($widget); } public function getDefaultTypeViewDataTable() diff --git a/plugins/Referrers/Reports/GetWebsites.php b/plugins/Referrers/Reports/GetWebsites.php index 18f9336a63..f5be3ca375 100644 --- a/plugins/Referrers/Reports/GetWebsites.php +++ b/plugins/Referrers/Reports/GetWebsites.php @@ -12,6 +12,8 @@ use Piwik\Piwik; use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\CoreVisualizations\Visualizations\HtmlTable; use Piwik\Plugins\Referrers\Columns\Website; +use Piwik\Report\ReportWidgetFactory; +use Piwik\Widget\WidgetsList; class GetWebsites extends Base { @@ -25,7 +27,8 @@ class GetWebsites extends Base $this->actionToLoadSubTables = 'getUrlsFromWebsiteId'; $this->hasGoalMetrics = true; $this->order = 5; - $this->widgetTitle = 'Referrers_WidgetExternalWebsites'; + + $this->subcategoryId = 'Referrers_SubmenuWebsites'; } public function configureView(ViewDataTable $view) diff --git a/plugins/Referrers/Widgets.php b/plugins/Referrers/Widgets.php deleted file mode 100644 index 4e23c9f746..0000000000 --- a/plugins/Referrers/Widgets.php +++ /dev/null @@ -1,24 +0,0 @@ -addWidget('Referrers_WidgetTopKeywordsForPages', 'getKeywordsForPage'); - } - } - -} diff --git a/plugins/Referrers/Widgets/GetKeywordsForPage.php b/plugins/Referrers/Widgets/GetKeywordsForPage.php new file mode 100644 index 0000000000..165bb18f68 --- /dev/null +++ b/plugins/Referrers/Widgets/GetKeywordsForPage.php @@ -0,0 +1,23 @@ +setCategoryId('SEO'); + $config->setName('Referrers_WidgetTopKeywordsForPages'); + $config->setIsEnabled(SettingsPiwik::isSegmentationEnabled()); + } + +} diff --git a/plugins/Referrers/templates/allReferrers.twig b/plugins/Referrers/templates/allReferrers.twig deleted file mode 100644 index bf8c7c431c..0000000000 --- a/plugins/Referrers/templates/allReferrers.twig +++ /dev/null @@ -1,11 +0,0 @@ -

    {{ 'Referrers_ReferrerTypes'|translate }}

    -{{ dataTableReferrerType|raw }} - -
    - -{% if totalVisits > 0 %} -

    {{ 'Referrers_Referrers'|translate }}

    - {{ referrersReportsByDimension|raw }} -{% endif %} - -{% include "_sparklineFooter.twig" %} diff --git a/plugins/Referrers/templates/getSearchEnginesAndKeywords.twig b/plugins/Referrers/templates/getSearchEnginesAndKeywords.twig deleted file mode 100644 index 29b2b3f0af..0000000000 --- a/plugins/Referrers/templates/getSearchEnginesAndKeywords.twig +++ /dev/null @@ -1,13 +0,0 @@ -
    - -
    -

    {{ 'Referrers_Keywords'|translate }}

    - {{ keywords|raw }} -
    - -
    -

    {{ 'Referrers_SearchEngines'|translate }}

    - {{ searchEngines|raw }} -
    - -
    diff --git a/plugins/Referrers/templates/index.twig b/plugins/Referrers/templates/index.twig deleted file mode 100644 index c629431210..0000000000 --- a/plugins/Referrers/templates/index.twig +++ /dev/null @@ -1,89 +0,0 @@ -

    {{ 'General_EvolutionOverPeriod'|translate }}

    -{{ graphEvolutionReferrers|raw }} - -

    {{ 'Referrers_Type'|translate }}

    - -
    -
    -
    {{ sparkline(urlSparklineDirectEntry) }} - {{ 'Referrers_TypeDirectEntries'|translate(""~visitorsFromDirectEntry~"")|raw }} - {% if visitorsFromDirectEntryPercent|default is not empty %}, - {{ 'Referrers_XPercentOfVisits'|translate(""~visitorsFromDirectEntryPercent~"")|raw }} - {% endif %} - {% if visitorsFromDirectEntryEvolution|default is not empty %} - {{ visitorsFromDirectEntryEvolution|raw }} - {% endif %} -
    -
    {{ sparkline(urlSparklineSearchEngines) }} - {{ 'Referrers_TypeSearchEngines'|translate(""~visitorsFromSearchEngines~"")|raw }} - {% if visitorsFromSearchEnginesPercent|default is not empty %}, - {{ 'Referrers_XPercentOfVisits'|translate(""~visitorsFromSearchEnginesPercent~"")|raw }} - {% endif %} - {% if visitorsFromSearchEnginesEvolution|default is not empty %} - {{ visitorsFromSearchEnginesEvolution|raw }} - {% endif %} -
    -
    -
    -
    {{ sparkline(urlSparklineWebsites) }} - {{ 'Referrers_TypeWebsites'|translate(""~visitorsFromWebsites~"")|raw }} - {% if visitorsFromWebsitesPercent|default is not empty %}, - {{ 'Referrers_XPercentOfVisits'|translate(""~visitorsFromWebsitesPercent~"")|raw }} - {% endif %} - {% if visitorsFromWebsitesEvolution|default is not empty %} - {{ visitorsFromWebsitesEvolution|raw }} - {% endif %} -
    -
    {{ sparkline(urlSparklineCampaigns) }} - {{ 'Referrers_TypeCampaigns'|translate(""~visitorsFromCampaigns~"")|raw }} - {% if visitorsFromCampaignsPercent|default is not empty %}, - {{ 'Referrers_XPercentOfVisits'|translate(""~visitorsFromCampaignsPercent~"")|raw }} - {% endif %} - {% if visitorsFromCampaignsEvolution|default is not empty %} - {{ visitorsFromCampaignsEvolution|raw }} - {% endif %} -
    -
    -
    - -
    -
    -
    {{ sparkline(urlSparklineDistinctSearchEngines) }} - {{ numberDistinctSearchEngines }} {{ 'Referrers_DistinctSearchEngines'|translate }} - {% if numberDistinctSearchEnginesEvolution|default is not empty %} - {{ numberDistinctSearchEnginesEvolution|raw }} - {% endif %} -
    -
    {{ sparkline(urlSparklineDistinctKeywords) }} - {{ numberDistinctKeywords }} {{ 'Referrers_DistinctKeywords'|translate }} - {% if numberDistinctKeywordsEvolution|default is not empty %} - {{ numberDistinctKeywordsEvolution|raw }} - {% endif %} -
    -
    -
    -
    {{ sparkline(urlSparklineDistinctWebsites) }} - {{ numberDistinctWebsites }} {{ 'Referrers_DistinctWebsites'|translate }} - {{ 'Referrers_UsingNDistinctUrls'|translate(""~numberDistinctWebsitesUrls~"")|raw }} - {% if numberDistinctWebsitesEvolution|default is not empty %} - {{ numberDistinctWebsitesEvolution|raw }} - {% endif %} -
    -
    {{ sparkline(urlSparklineDistinctCampaigns) }} - {{ numberDistinctCampaigns }} {{ 'Referrers_DistinctCampaigns'|translate }} - {% if numberDistinctCampaignsEvolution|default is not empty %} - {{ numberDistinctCampaignsEvolution|raw }} - {% endif %} -
    -
    -
    -
    - - - -{% include "_sparklineFooter.twig" %} diff --git a/plugins/Referrers/templates/indexWebsites.twig b/plugins/Referrers/templates/indexWebsites.twig deleted file mode 100644 index cdfa6efe01..0000000000 --- a/plugins/Referrers/templates/indexWebsites.twig +++ /dev/null @@ -1,13 +0,0 @@ -
    - -
    -

    {{ 'Referrers_Websites'|translate }}

    - {{ websites|raw }} -
    - -
    -

    {{ 'Referrers_Socials'|translate }}

    - {{ socials|raw }} -
    - -
    diff --git a/plugins/Resolution/Reports/Base.php b/plugins/Resolution/Reports/Base.php index 259a164113..0ef3f0d631 100644 --- a/plugins/Resolution/Reports/Base.php +++ b/plugins/Resolution/Reports/Base.php @@ -15,7 +15,7 @@ abstract class Base extends \Piwik\Plugin\Report { protected function init() { - $this->category = 'General_VisitorSettings'; + $this->categoryId = 'General_Visitors'; } protected function getBasicResolutionDisplayProperties(ViewDataTable $view) diff --git a/plugins/Resolution/Reports/GetConfiguration.php b/plugins/Resolution/Reports/GetConfiguration.php index c01c4f3b07..600f07edd9 100644 --- a/plugins/Resolution/Reports/GetConfiguration.php +++ b/plugins/Resolution/Reports/GetConfiguration.php @@ -11,6 +11,7 @@ namespace Piwik\Plugins\Resolution\Reports; use Piwik\Piwik; use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\Resolution\Columns\Configuration; +use Piwik\Plugin\Reports; class GetConfiguration extends Base { @@ -18,10 +19,11 @@ class GetConfiguration extends Base { parent::init(); $this->dimension = new Configuration(); - $this->name = Piwik::translate('Resolution_WidgetGlobalVisitors'); + $this->name = Piwik::translate('Resolution_Configurations'); $this->documentation = Piwik::translate('Resolution_WidgetGlobalVisitorsDocumentation', '
    '); $this->order = 7; - $this->widgetTitle = 'Resolution_WidgetGlobalVisitors'; + + $this->subcategoryId = 'DevicesDetection_Software'; } public function configureView(ViewDataTable $view) @@ -36,7 +38,7 @@ class GetConfiguration extends Base public function getRelatedReports() { return array( - self::factory('Resolution', 'getResolution'), + Reports::factory('Resolution', 'getResolution'), ); } } diff --git a/plugins/Resolution/Reports/GetResolution.php b/plugins/Resolution/Reports/GetResolution.php index f9066ce19c..3b27236a86 100644 --- a/plugins/Resolution/Reports/GetResolution.php +++ b/plugins/Resolution/Reports/GetResolution.php @@ -11,6 +11,7 @@ namespace Piwik\Plugins\Resolution\Reports; use Piwik\Piwik; use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\Resolution\Columns\Resolution; +use Piwik\Plugin\Reports; class GetResolution extends Base { @@ -20,8 +21,9 @@ class GetResolution extends Base $this->dimension = new Resolution(); $this->name = Piwik::translate('Resolution_WidgetResolutions'); $this->documentation = ''; // TODO - $this->order = 0; - $this->widgetTitle = 'Resolution_WidgetResolutions'; + $this->order = 8; + + $this->subcategoryId = 'DevicesDetection_Devices'; } public function configureView(ViewDataTable $view) @@ -34,7 +36,7 @@ class GetResolution extends Base public function getRelatedReports() { return array( - self::factory('Resolution', 'getConfiguration'), + Reports::factory('Resolution', 'getConfiguration'), ); } } diff --git a/plugins/SEO/Widgets.php b/plugins/SEO/Widgets.php deleted file mode 100644 index 1f06c2ec8b..0000000000 --- a/plugins/SEO/Widgets.php +++ /dev/null @@ -1,55 +0,0 @@ -addWidget('SEO_SeoRankings', 'getRank'); - } - - public function getRank() - { - $idSite = Common::getRequestVar('idSite'); - $site = new Site($idSite); - - $url = urldecode(Common::getRequestVar('url', '', 'string')); - - if (!empty($url) && strpos($url, 'http://') !== 0 && strpos($url, 'https://') !== 0) { - $url = 'http://' . $url; - } - - if (empty($url) || !UrlHelper::isLookLikeUrl($url)) { - $url = $site->getMainUrl(); - } - - $dataTable = API::getInstance()->getRank($url); - - $view = new View('@SEO/getRank'); - $view->urlToRank = Url::getHostFromUrl($url); - - /** @var \Piwik\DataTable\Renderer\Php $renderer */ - $renderer = Renderer::factory('php'); - $renderer->setSerialize(false); - $view->ranks = $renderer->render($dataTable); - - return $view->render(); - } - -} diff --git a/plugins/SEO/Widgets/GetRank.php b/plugins/SEO/Widgets/GetRank.php new file mode 100644 index 0000000000..521bf1859c --- /dev/null +++ b/plugins/SEO/Widgets/GetRank.php @@ -0,0 +1,56 @@ +setCategoryId('SEO'); + $config->setName('SEO_SeoRankings'); + } + + public function render() + { + $idSite = Common::getRequestVar('idSite'); + $site = new Site($idSite); + + $url = urldecode(Common::getRequestVar('url', '', 'string')); + + if (!empty($url) && strpos($url, 'http://') !== 0 && strpos($url, 'https://') !== 0) { + $url = 'http://' . $url; + } + + if (empty($url) || !UrlHelper::isLookLikeUrl($url)) { + $url = $site->getMainUrl(); + } + + $dataTable = API::getInstance()->getRank($url); + + $view = new View('@SEO/getRank'); + $view->urlToRank = Url::getHostFromUrl($url); + + /** @var \Piwik\DataTable\Renderer\Php $renderer */ + $renderer = Renderer::factory('php'); + $renderer->setSerialize(false); + $view->ranks = $renderer->render($dataTable); + + return $view->render(); + } + +} diff --git a/plugins/Transitions/Controller.php b/plugins/Transitions/Controller.php index dbd782f08c..fb7bb5de2b 100644 --- a/plugins/Transitions/Controller.php +++ b/plugins/Transitions/Controller.php @@ -22,7 +22,7 @@ class Controller extends \Piwik\Plugin\Controller * translation keys. */ private static $metricTranslations = array( - 'pageviewsInline' => 'VisitsSummary_NbPageviewsDescription', + 'pageviewsInline' => 'Transitions_NumPageviews', 'loopsInline' => 'Transitions_LoopsInline', 'fromPreviousPages' => 'Transitions_FromPreviousPages', 'fromPreviousPagesInline' => 'Transitions_FromPreviousPagesInline', @@ -41,9 +41,9 @@ class Controller extends \Piwik\Plugin\Controller 'toFollowingSiteSearches' => 'Transitions_ToFollowingSiteSearches', 'toFollowingSiteSearchesInline' => 'Transitions_ToFollowingSiteSearchesInline', 'downloads' => 'General_Downloads', - 'downloadsInline' => 'VisitsSummary_NbDownloadsDescription', + 'downloadsInline' => 'Transitions_NumDownloads', 'outlinks' => 'General_Outlinks', - 'outlinksInline' => 'VisitsSummary_NbOutlinksDescription', + 'outlinksInline' => 'Transitions_NumOutlinks', 'exits' => 'General_ColumnExits', 'exitsInline' => 'Transitions_ExitsInline', 'bouncesInline' => 'Transitions_BouncesInline' diff --git a/plugins/Transitions/lang/en.json b/plugins/Transitions/lang/en.json index 4e76d5bc54..af45334071 100644 --- a/plugins/Transitions/lang/en.json +++ b/plugins/Transitions/lang/en.json @@ -4,6 +4,9 @@ "DirectEntries": "Direct Entries", "ErrorBack": "Go back to the previous action", "ExitsInline": "%s exits", + "NumPageviews": "%s pageviews", + "NumDownloads": "%s downloads", + "NumOutlinks": "%s outlinks", "FromCampaigns": "From Campaigns", "FromPreviousPages": "From Internal Pages", "FromPreviousPagesInline": "%s from internal pages", diff --git a/plugins/UserCountry/Categories/LocationsSubcategory.php b/plugins/UserCountry/Categories/LocationsSubcategory.php new file mode 100644 index 0000000000..22be202abd --- /dev/null +++ b/plugins/UserCountry/Categories/LocationsSubcategory.php @@ -0,0 +1,19 @@ +urlSparklineCountries = $this->getUrlSparkline('getLastDistinctCountriesGraph'); $view->numberDistinctCountries = $this->getNumberOfDistinctCountries(true); - $view->dataTableCountry = $this->renderReport('getCountry'); - $view->dataTableContinent = $this->renderReport('getContinent'); - $view->dataTableRegion = $this->renderReport('getRegion'); - $view->dataTableCity = $this->renderReport('getCity'); - return $view->render(); } diff --git a/plugins/UserCountry/Menu.php b/plugins/UserCountry/Menu.php index fa90e258db..92f88a7f14 100644 --- a/plugins/UserCountry/Menu.php +++ b/plugins/UserCountry/Menu.php @@ -9,7 +9,6 @@ namespace Piwik\Plugins\UserCountry; use Piwik\Menu\MenuAdmin; -use Piwik\Menu\MenuReporting; use Piwik\Piwik; class Menu extends \Piwik\Plugin\Menu @@ -22,9 +21,4 @@ class Menu extends \Piwik\Plugin\Menu $order = 9); } } - - public function configureReportingMenu(MenuReporting $menu) - { - $menu->addVisitorsItem('UserCountry_SubmenuLocations', $this->urlForAction('index')); - } } diff --git a/plugins/UserCountry/Reports/Base.php b/plugins/UserCountry/Reports/Base.php index f7a4f34203..c24ec82d24 100644 --- a/plugins/UserCountry/Reports/Base.php +++ b/plugins/UserCountry/Reports/Base.php @@ -17,7 +17,7 @@ abstract class Base extends \Piwik\Plugin\Report { protected function init() { - $this->category = 'General_Visitors'; + $this->categoryId = 'General_Visitors'; } protected function getGeoIPReportDocSuffix() diff --git a/plugins/UserCountry/Reports/GetCity.php b/plugins/UserCountry/Reports/GetCity.php index ce087c3f3c..e492d12ee2 100644 --- a/plugins/UserCountry/Reports/GetCity.php +++ b/plugins/UserCountry/Reports/GetCity.php @@ -22,9 +22,8 @@ class GetCity extends Base $this->documentation = Piwik::translate('UserCountry_getCityDocumentation') . '
    ' . $this->getGeoIPReportDocSuffix(); $this->metrics = array('nb_visits', 'nb_uniq_visitors', 'nb_actions'); $this->hasGoalMetrics = true; - $this->order = 8; - $this->widgetTitle = Piwik::translate('UserCountry_WidgetLocation') - . ' (' . Piwik::translate('UserCountry_City') . ')'; + $this->order = 10; + $this->subcategoryId = 'UserCountry_SubmenuLocations'; } public function configureView(ViewDataTable $view) diff --git a/plugins/UserCountry/Reports/GetContinent.php b/plugins/UserCountry/Reports/GetContinent.php index 7ba6d2ca1c..b524c4f048 100644 --- a/plugins/UserCountry/Reports/GetContinent.php +++ b/plugins/UserCountry/Reports/GetContinent.php @@ -11,6 +11,9 @@ namespace Piwik\Plugins\UserCountry\Reports; use Piwik\Piwik; use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\UserCountry\Columns\Continent; +use Piwik\Report\ReportWidgetFactory; +use Piwik\Widget\WidgetContainerConfig; +use Piwik\Widget\WidgetsList; class GetContinent extends Base { @@ -23,8 +26,18 @@ class GetContinent extends Base $this->metrics = array('nb_visits', 'nb_uniq_visitors', 'nb_actions'); $this->hasGoalMetrics = true; $this->order = 6; - $this->widgetTitle = Piwik::translate('UserCountry_WidgetLocation') - . ' (' . Piwik::translate('UserCountry_Continent') . ')'; + + $this->subcategoryId = 'UserCountry_SubmenuLocations'; + } + + public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory) + { + $widgetsList->addWidgetConfig($factory->createContainerWidget('Continent')); + + $widgetsList->addToContainerWidget('Continent', $factory->createWidget()); + + $widget = $factory->createWidget()->setAction('getDistinctCountries')->setName(''); + $widgetsList->addToContainerWidget('Continent', $widget); } public function configureView(ViewDataTable $view) diff --git a/plugins/UserCountry/Reports/GetCountry.php b/plugins/UserCountry/Reports/GetCountry.php index 88363e1efa..5b038f7e49 100644 --- a/plugins/UserCountry/Reports/GetCountry.php +++ b/plugins/UserCountry/Reports/GetCountry.php @@ -24,8 +24,7 @@ class GetCountry extends Base $this->metrics = array('nb_visits', 'nb_uniq_visitors', 'nb_actions'); $this->hasGoalMetrics = true; $this->order = 5; - $this->widgetTitle = Piwik::translate('UserCountry_WidgetLocation') - . ' (' . Piwik::translate('UserCountry_Country') . ')'; + $this->subcategoryId = 'UserCountry_SubmenuLocations'; } public function configureView(ViewDataTable $view) diff --git a/plugins/UserCountry/Reports/GetRegion.php b/plugins/UserCountry/Reports/GetRegion.php index 648b78967b..7e418ebef2 100644 --- a/plugins/UserCountry/Reports/GetRegion.php +++ b/plugins/UserCountry/Reports/GetRegion.php @@ -23,8 +23,8 @@ class GetRegion extends Base $this->metrics = array('nb_visits', 'nb_uniq_visitors', 'nb_actions'); $this->hasGoalMetrics = true; $this->order = 7; - $this->widgetTitle = Piwik::translate('UserCountry_WidgetLocation') - . ' (' . Piwik::translate('UserCountry_Region') . ')'; + + $this->subcategoryId = 'UserCountry_SubmenuLocations'; } public function configureView(ViewDataTable $view) diff --git a/plugins/UserCountry/templates/getDistinctCountries.twig b/plugins/UserCountry/templates/getDistinctCountries.twig new file mode 100644 index 0000000000..7a2506f782 --- /dev/null +++ b/plugins/UserCountry/templates/getDistinctCountries.twig @@ -0,0 +1,5 @@ +
    + {{ sparkline(urlSparklineCountries) }} + {{ 'UserCountry_DistinctCountries'|translate(""~numberDistinctCountries~"")|raw }} +
    +
    \ No newline at end of file diff --git a/plugins/UserCountry/templates/index.twig b/plugins/UserCountry/templates/index.twig deleted file mode 100644 index fe1a6735dd..0000000000 --- a/plugins/UserCountry/templates/index.twig +++ /dev/null @@ -1,29 +0,0 @@ -
    - -
    - {{ postEvent("Template.leftColumnUserCountry") }} - -

    {{ 'UserCountry_Continent'|translate }}

    - {{ dataTableContinent|raw }} - -
    - {{ sparkline(urlSparklineCountries) }} - {{ 'UserCountry_DistinctCountries'|translate(""~numberDistinctCountries~"")|raw }} -
    -
    - - {{ postEvent("Template.footerUserCountry") }} -
    - -
    -

    {{ 'UserCountry_Country'|translate }}

    - {{ dataTableCountry|raw }} - -

    {{ 'UserCountry_Region'|translate }}

    - {{ dataTableRegion|raw }} - -

    {{ 'UserCountry_City'|translate }}

    - {{ dataTableCity|raw }} -
    - -
    diff --git a/plugins/UserCountryMap/Categories/RealTimeMapSubcategory.php b/plugins/UserCountryMap/Categories/RealTimeMapSubcategory.php new file mode 100644 index 0000000000..d8f482327f --- /dev/null +++ b/plugins/UserCountryMap/Categories/RealTimeMapSubcategory.php @@ -0,0 +1,19 @@ +isPluginActivated('UserCountry')) { - $menu->addVisitorsItem('UserCountryMap_RealTimeMap', - $this->urlForAction('realtimeWorldMap'), - $order = 70); - } - } -} diff --git a/plugins/UserCountryMap/UserCountryMap.php b/plugins/UserCountryMap/UserCountryMap.php index c7819f7f8c..6453cc7f29 100644 --- a/plugins/UserCountryMap/UserCountryMap.php +++ b/plugins/UserCountryMap/UserCountryMap.php @@ -10,8 +10,9 @@ namespace Piwik\Plugins\UserCountryMap; use Piwik\FrontController; use Piwik\Piwik; +use Piwik\Widget\WidgetConfig; use Piwik\Version; -use Piwik\WidgetsList; +use Piwik\Widget\WidgetsList; use Piwik\Plugin\Manager as PluginManager; /** @@ -34,23 +35,11 @@ class UserCountryMap extends \Piwik\Plugin $hooks = array( 'AssetManager.getJavaScriptFiles' => 'getJsFiles', 'AssetManager.getStylesheetFiles' => 'getStylesheetFiles', - 'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys', - 'Platform.initialized' => array( - 'after' => true, - 'function' => 'registerWidgets' - ) + 'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys' ); return $hooks; } - public function registerWidgets() - { - if (PluginManager::getInstance()->isPluginActivated('UserCountry')) { - WidgetsList::add('General_Visitors', Piwik::translate('UserCountryMap_VisitorMap'), 'UserCountryMap', 'visitorMap'); - WidgetsList::add('Live!', Piwik::translate('UserCountryMap_RealTimeMap'), 'UserCountryMap', 'realtimeMap'); - } - } - public function getJsFiles(&$jsFiles) { $jsFiles[] = "libs/bower_components/visibilityjs/lib/visibility.core.js"; diff --git a/plugins/UserCountryMap/Widgets/GetRealtimeMap.php b/plugins/UserCountryMap/Widgets/GetRealtimeMap.php new file mode 100644 index 0000000000..d6476bfe2d --- /dev/null +++ b/plugins/UserCountryMap/Widgets/GetRealtimeMap.php @@ -0,0 +1,29 @@ +setCategoryId('General_Visitors'); + $config->setSubcategoryId('UserCountryMap_RealTimeMap'); + $config->setName('UserCountryMap_RealTimeMap'); + $config->setModule('UserCountryMap'); + $config->setAction('realtimeMap'); + $config->setOrder(5); + + if (!PluginManager::getInstance()->isPluginActivated('UserCountry')) { + $config->disable(); + } + } +} diff --git a/plugins/UserCountryMap/Widgets/GetVisitorMap.php b/plugins/UserCountryMap/Widgets/GetVisitorMap.php new file mode 100644 index 0000000000..930630df55 --- /dev/null +++ b/plugins/UserCountryMap/Widgets/GetVisitorMap.php @@ -0,0 +1,23 @@ +setCategoryId('General_Visitors'); + $config->setSubcategoryId('UserCountry_SubmenuLocations'); + $config->setName('UserCountryMap_VisitorMap'); + $config->setAction('visitorMap'); + $config->setOrder(1); + } +} diff --git a/plugins/UserCountryMap/templates/visitorMap.twig b/plugins/UserCountryMap/templates/visitorMap.twig index 7873200c9f..b5445a2cc6 100644 --- a/plugins/UserCountryMap/templates/visitorMap.twig +++ b/plugins/UserCountryMap/templates/visitorMap.twig @@ -86,7 +86,7 @@ if ($('#dashboardWidgetsArea').length) { // dashboard mode - var $widgetContent = $('.UserCountryMap').parents('.widgetContent'); + var $widgetContent = $('.UserCountryMap').parents('.widgetContent').first(); $widgetContent.on('widget:create',function (evt, widget) { visitorMap = new UserCountryMap.VisitorMap(config, widget); diff --git a/plugins/UserLanguage/Reports/Base.php b/plugins/UserLanguage/Reports/Base.php index 366521b16a..68e8a91b4b 100644 --- a/plugins/UserLanguage/Reports/Base.php +++ b/plugins/UserLanguage/Reports/Base.php @@ -15,6 +15,7 @@ abstract class Base extends \Piwik\Plugin\Report { protected function init() { - $this->category = 'General_VisitorSettings'; + $this->categoryId = 'General_Visitors'; + $this->subcategoryId = 'UserCountry_SubmenuLocations'; } } diff --git a/plugins/UserLanguage/Reports/GetLanguage.php b/plugins/UserLanguage/Reports/GetLanguage.php index f5babd65b8..8db3629134 100644 --- a/plugins/UserLanguage/Reports/GetLanguage.php +++ b/plugins/UserLanguage/Reports/GetLanguage.php @@ -11,6 +11,7 @@ namespace Piwik\Plugins\UserLanguage\Reports; use Piwik\Piwik; use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\UserLanguage\Columns\Language; +use Piwik\Plugin\Reports; class GetLanguage extends Base { @@ -20,8 +21,7 @@ class GetLanguage extends Base $this->dimension = new Language(); $this->name = Piwik::translate('UserLanguage_BrowserLanguage'); $this->documentation = ''; // TODO - $this->order = 10; - $this->widgetTitle = 'UserLanguage_BrowserLanguage'; + $this->order = 8; } public function configureView(ViewDataTable $view) @@ -37,7 +37,7 @@ class GetLanguage extends Base public function getRelatedReports() { return array( - self::factory('UserLanguage', 'getLanguageCode'), + Reports::factory('UserLanguage', 'getLanguageCode'), ); } diff --git a/plugins/UserLanguage/Reports/GetLanguageCode.php b/plugins/UserLanguage/Reports/GetLanguageCode.php index 0ca2c64bb2..9d9a46f201 100644 --- a/plugins/UserLanguage/Reports/GetLanguageCode.php +++ b/plugins/UserLanguage/Reports/GetLanguageCode.php @@ -10,6 +10,7 @@ namespace Piwik\Plugins\UserLanguage\Reports; use Piwik\Piwik; use Piwik\Plugins\UserLanguage\Columns\Language; +use Piwik\Plugin\Reports; class GetLanguageCode extends GetLanguage { @@ -20,13 +21,12 @@ class GetLanguageCode extends GetLanguage $this->name = Piwik::translate('UserLanguage_LanguageCode'); $this->documentation = ''; $this->order = 11; - $this->widgetTitle = 'UserLanguage_LanguageCode'; } public function getRelatedReports() { return array( - self::factory('UserLanguage', 'getLanguage'), + Reports::factory('UserLanguage', 'getLanguage'), ); } diff --git a/plugins/VisitFrequency/Controller.php b/plugins/VisitFrequency/Controller.php index e1279206fd..8e6af9cffd 100644 --- a/plugins/VisitFrequency/Controller.php +++ b/plugins/VisitFrequency/Controller.php @@ -8,9 +8,10 @@ */ namespace Piwik\Plugins\VisitFrequency; -use Piwik\API\Request; use Piwik\Common; +use Piwik\FrontController; use Piwik\Piwik; +use Piwik\Plugins\CoreVisualizations\Visualizations\Sparklines; use Piwik\Translation\Translator; use Piwik\View; @@ -28,31 +29,22 @@ class Controller extends \Piwik\Plugin\Controller parent::__construct(); } - public function index() - { - $view = new View('@VisitFrequency/index'); - $this->setGeneralVariablesView($view); - - $view->graphEvolutionVisitFrequency = $this->getEvolutionGraph(array(), array('nb_visits_returning')); - $this->setSparklinesAndNumbers($view); - - return $view->render(); - } - + /** + * @deprecated used to be a widgetized URL. There to not break widget URLs + */ public function getSparklines() { - $view = new View('@VisitFrequency/getSparklines'); - $this->setSparklinesAndNumbers($view); - return $view->render(); + $_GET['forceView'] = '1'; + $_GET['viewDataTable'] = Sparklines::ID; + + return FrontController::getInstance()->fetchDispatch('VisitFrequency', 'get'); } - public function getEvolutionGraph(array $columns = array(), array $defaultColumns = array()) + public function getEvolutionGraph() { - if (empty($columns)) { - $columns = Common::getRequestVar('columns', false); - if (false !== $columns) { - $columns = Piwik::getArrayFromApiParameter($columns); - } + $columns = Common::getRequestVar('columns', false); + if (false !== $columns) { + $columns = Piwik::getArrayFromApiParameter($columns); } $documentation = $this->translator->translate('VisitFrequency_ReturningVisitsDocumentation') . '
    ' @@ -89,35 +81,10 @@ class Controller extends \Piwik\Plugin\Controller $view = $this->getLastUnitGraphAcrossPlugins($this->pluginName, __FUNCTION__, $columns, $selectableColumns, $documentation); - if (empty($view->config->columns_to_display) && !empty($defaultColumns)) { - $view->config->columns_to_display = $defaultColumns; + if (empty($view->config->columns_to_display)) { + $view->config->columns_to_display = array('nb_visits_returning'); } return $this->renderView($view); } - - protected function setSparklinesAndNumbers($view) - { - $view->urlSparklineNbVisitsReturning = $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('nb_visits_returning'))); - $view->urlSparklineNbActionsReturning = $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('nb_actions_returning'))); - $view->urlSparklineActionsPerVisitReturning = $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('nb_actions_per_visit_returning'))); - $view->urlSparklineAvgVisitDurationReturning = $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('avg_time_on_site_returning'))); - $view->urlSparklineBounceRateReturning = $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('bounce_rate_returning'))); - - $dataTableFrequency = $this->getSummary(); - $dataRow = $dataTableFrequency->getFirstRow(); - $nbVisitsReturning = $dataRow->getColumn('nb_visits_returning'); - $view->nbVisitsReturning = $nbVisitsReturning; - $view->nbActionsReturning = $dataRow->getColumn('nb_actions_returning'); - $view->nbActionsPerVisitReturning = $dataRow->getColumn('nb_actions_per_visit_returning'); - $view->avgVisitDurationReturning = $dataRow->getColumn('avg_time_on_site_returning'); - $view->bounceRateReturning = $dataRow->getColumn('bounce_rate_returning'); - } - - protected function getSummary() - { - $requestString = "method=VisitFrequency.get&format=original"; - $request = new Request($requestString); - return $request->process(); - } } diff --git a/plugins/VisitFrequency/Menu.php b/plugins/VisitFrequency/Menu.php deleted file mode 100644 index e858bd2f76..0000000000 --- a/plugins/VisitFrequency/Menu.php +++ /dev/null @@ -1,19 +0,0 @@ -addVisitorsItem('VisitFrequency_SubmenuFrequency', $this->urlForAction('index'), $order = 55); - } -} diff --git a/plugins/VisitFrequency/Reports/Get.php b/plugins/VisitFrequency/Reports/Get.php index eb4c7ddfbe..735f1cbe0f 100644 --- a/plugins/VisitFrequency/Reports/Get.php +++ b/plugins/VisitFrequency/Reports/Get.php @@ -9,17 +9,22 @@ namespace Piwik\Plugins\VisitFrequency\Reports; use Piwik\Piwik; +use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\CoreHome\Columns\Metrics\ActionsPerVisit; use Piwik\Plugins\CoreHome\Columns\Metrics\AverageTimeOnSite; use Piwik\Plugins\CoreHome\Columns\Metrics\BounceRate; +use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Evolution; +use Piwik\Plugins\CoreVisualizations\Visualizations\Sparklines; use Piwik\Plugins\VisitFrequency\Columns\Metrics\ReturningMetric; +use Piwik\Report\ReportWidgetFactory; +use Piwik\Widget\WidgetsList; class Get extends \Piwik\Plugin\Report { protected function init() { parent::init(); - $this->category = 'General_Visitors'; + $this->categoryId = 'General_Visitors'; $this->name = Piwik::translate('VisitFrequency_ColumnReturningVisits'); $this->documentation = ''; // TODO $this->processedMetrics = array( @@ -35,5 +40,60 @@ class Get extends \Piwik\Plugin\Report 'max_actions_returning' ); $this->order = 40; + $this->subcategoryId = 'VisitorInterest_Engagement'; } + + public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory) + { + $widgetsList->addWidgetConfig( + $factory->createWidget() + ->setName('VisitFrequency_WidgetGraphReturning') + ->forceViewDataTable(Evolution::ID) + ->setAction('getEvolutionGraph') + ->setOrder(1) + ); + + $widgetsList->addWidgetConfig( + $factory->createWidget() + ->forceViewDataTable(Sparklines::ID) + ->setName('VisitFrequency_WidgetOverview') + ->setOrder(2) + ); + } + + public function configureView(ViewDataTable $view) + { + if ($view->isViewDataTableId(Sparklines::ID)) { + $view->requestConfig->apiMethodToRequestDataTable = 'VisitFrequency.get'; + $this->addSparklineColumns($view); + $view->config->addTranslations($this->getSparklineTranslations()); + } + } + + private function getSparklineTranslations() + { + $translations = array( + 'nb_visits_returning' => 'ReturnVisits', + 'nb_actions_returning' => 'ReturnActions', + 'nb_actions_per_visit_returning' => 'ReturnAvgActions', + 'avg_time_on_site_returning' => 'ReturnAverageVisitDuration', + 'bounce_rate_returning' => 'ReturnBounceRate', + ); + + foreach ($translations as $metric => $key) { + $translations[$metric] = Piwik::translate('VisitFrequency_' . $key); + } + + return $translations; + } + + private function addSparklineColumns(Sparklines $view) + { + $view->config->addSparklineMetric(array('nb_visits_returning')); + $view->config->addSparklineMetric(array('avg_time_on_site_returning')); + $view->config->addSparklineMetric(array('nb_actions_per_visit_returning')); + $view->config->addSparklineMetric(array('bounce_rate_returning')); + $view->config->addSparklineMetric(array('nb_actions_returning')); + } + } diff --git a/plugins/VisitFrequency/Widgets.php b/plugins/VisitFrequency/Widgets.php deleted file mode 100644 index 53a5ddcd47..0000000000 --- a/plugins/VisitFrequency/Widgets.php +++ /dev/null @@ -1,23 +0,0 @@ -addWidget('VisitFrequency_WidgetOverview', 'getSparklines'); - $this->addWidget('VisitFrequency_WidgetGraphReturning', - 'getEvolutionGraph', - array('columns' => array('nb_visits_returning'))); - } - -} diff --git a/plugins/VisitFrequency/lang/en.json b/plugins/VisitFrequency/lang/en.json index d157e0a88c..39b1879852 100644 --- a/plugins/VisitFrequency/lang/en.json +++ b/plugins/VisitFrequency/lang/en.json @@ -12,13 +12,13 @@ "ColumnUniqueReturningVisitors": "Unique returning visitors", "ColumnReturningUsers": "Returning Users", "PluginDescription": "Reports metrics about your first time new visitors and returning visitors.", - "ReturnActions": "%s actions by the returning visits", - "ReturnAverageVisitDuration": "%s average visit duration for returning visitors", - "ReturnAvgActions": "%s actions per returning visit", - "ReturnBounceRate": "%s returning visits have bounced (left the website after one page)", + "ReturnActions": "actions by the returning visits", + "ReturnAverageVisitDuration": "average visit duration for returning visitors", + "ReturnAvgActions": "actions per returning visit", + "ReturnBounceRate": "returning visits have bounced (left the website after one page)", "ReturningVisitDocumentation": "A returning visit is (as opposed to a new visit) made by someone who has visited the website at least once before.", "ReturningVisitsDocumentation": "This is an overview of the returning visits.", - "ReturnVisits": "%s returning visits", + "ReturnVisits": "returning visits", "SubmenuFrequency": "Frequency", "WidgetGraphReturning": "Returning Visits Over Time", "WidgetOverview": "Frequency Overview" diff --git a/plugins/VisitFrequency/templates/_sparklines.twig b/plugins/VisitFrequency/templates/_sparklines.twig deleted file mode 100644 index c6c123c5e2..0000000000 --- a/plugins/VisitFrequency/templates/_sparklines.twig +++ /dev/null @@ -1,39 +0,0 @@ - -{% if not isWidget %} -
    -
    -{% endif %} - -
    - {{ sparkline(urlSparklineNbVisitsReturning) }} - {{ 'VisitFrequency_ReturnVisits'|translate(""~nbVisitsReturning~"")|raw }} -
    -
    - {{ sparkline(urlSparklineNbActionsReturning) }} - {{ 'VisitFrequency_ReturnActions'|translate(""~nbActionsReturning~"")|raw }} -
    -
    - {{ sparkline(urlSparklineActionsPerVisitReturning) }} - {{ 'VisitFrequency_ReturnAvgActions'|translate(""~nbActionsPerVisitReturning~"")|raw }} -
    - - {% if not isWidget %} -
    -
    - {% endif %} - -
    - {{ sparkline(urlSparklineAvgVisitDurationReturning) }} - {% set avgVisitDurationReturning=avgVisitDurationReturning|sumtime %} - {{ 'VisitFrequency_ReturnAverageVisitDuration'|translate(""~avgVisitDurationReturning~"")|raw }} -
    -
    - {{ sparkline(urlSparklineBounceRateReturning) }} - {{ 'VisitFrequency_ReturnBounceRate'|translate(""~bounceRateReturning~"")|raw }} -
    - {% include "_sparklineFooter.twig" %} - -{% if not isWidget %} -
    -
    -{% endif %} diff --git a/plugins/VisitFrequency/templates/getSparklines.twig b/plugins/VisitFrequency/templates/getSparklines.twig deleted file mode 100644 index fd158c8329..0000000000 --- a/plugins/VisitFrequency/templates/getSparklines.twig +++ /dev/null @@ -1 +0,0 @@ -{% include "@VisitFrequency/_sparklines.twig" %} \ No newline at end of file diff --git a/plugins/VisitFrequency/templates/index.twig b/plugins/VisitFrequency/templates/index.twig deleted file mode 100644 index 6abd255b17..0000000000 --- a/plugins/VisitFrequency/templates/index.twig +++ /dev/null @@ -1,9 +0,0 @@ -{{ postEvent("Template.headerVisitsFrequency") }} - -

    {{ 'VisitFrequency_ColumnReturningVisits'|translate }}

    - {{ graphEvolutionVisitFrequency|raw }} -
    - -{% include "@VisitFrequency/_sparklines.twig" %} - -{{ postEvent("Template.footerVisitsFrequency") }} diff --git a/plugins/VisitTime/Categories/TimesSubcategory.php b/plugins/VisitTime/Categories/TimesSubcategory.php new file mode 100644 index 0000000000..220a568ad3 --- /dev/null +++ b/plugins/VisitTime/Categories/TimesSubcategory.php @@ -0,0 +1,19 @@ +dataTableVisitInformationPerLocalTime = $this->renderReport('getVisitInformationPerLocalTime'); - $view->dataTableVisitInformationPerServerTime = $this->renderReport('getVisitInformationPerServerTime'); - return $view->render(); - } -} diff --git a/plugins/VisitTime/Menu.php b/plugins/VisitTime/Menu.php deleted file mode 100644 index ffa3a5b015..0000000000 --- a/plugins/VisitTime/Menu.php +++ /dev/null @@ -1,19 +0,0 @@ -addVisitorsItem('VisitTime_SubmenuTimes', $this->urlForAction('index'), $order = 65); - } -} diff --git a/plugins/VisitTime/Reports/Base.php b/plugins/VisitTime/Reports/Base.php index 89b553cd44..2dfbf0e169 100644 --- a/plugins/VisitTime/Reports/Base.php +++ b/plugins/VisitTime/Reports/Base.php @@ -15,7 +15,7 @@ abstract class Base extends \Piwik\Plugin\Report { protected function init() { - $this->category = 'VisitsSummary_VisitsSummary'; + $this->categoryId = 'General_Visitors'; } public function getDefaultTypeViewDataTable() diff --git a/plugins/VisitTime/Reports/GetByDayOfWeek.php b/plugins/VisitTime/Reports/GetByDayOfWeek.php index d9a3a58ee8..a93c6f21ee 100644 --- a/plugins/VisitTime/Reports/GetByDayOfWeek.php +++ b/plugins/VisitTime/Reports/GetByDayOfWeek.php @@ -14,6 +14,7 @@ use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\CoreVisualizations\Visualizations\Graph; use Piwik\Plugins\VisitTime\Columns\DayOfTheWeek; use Piwik\Period; +use Piwik\Plugin\Reports; use Piwik\Site; class GetByDayOfWeek extends Base @@ -28,7 +29,7 @@ class GetByDayOfWeek extends Base $this->documentation = Piwik::translate('VisitTime_WidgetByDayOfWeekDocumentation'); $this->constantRowsCount = true; $this->order = 25; - $this->widgetTitle = 'VisitTime_VisitsByDayOfWeek'; + $this->subcategoryId = 'VisitTime_SubmenuTimes'; } public function configureView(ViewDataTable $view) @@ -73,4 +74,11 @@ class GetByDayOfWeek extends Base } return $dateRange; } + + public function getRelatedReports() + { + return array( + Reports::factory('VisitTime', 'getVisitInformationPerLocalTime') + ); + } } diff --git a/plugins/VisitTime/Reports/GetVisitInformationPerLocalTime.php b/plugins/VisitTime/Reports/GetVisitInformationPerLocalTime.php index 6546463cd1..9372875619 100644 --- a/plugins/VisitTime/Reports/GetVisitInformationPerLocalTime.php +++ b/plugins/VisitTime/Reports/GetVisitInformationPerLocalTime.php @@ -13,6 +13,7 @@ use Piwik\Piwik; use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\CoreVisualizations\Visualizations\Graph; use Piwik\Plugins\VisitTime\Columns\LocalTime; +use Piwik\Plugin\Reports; class GetVisitInformationPerLocalTime extends Base { @@ -23,11 +24,12 @@ class GetVisitInformationPerLocalTime extends Base { parent::init(); $this->dimension = new LocalTime(); - $this->name = Piwik::translate('VisitTime_WidgetLocalTime'); + $this->name = Piwik::translate('VisitTime_LocalTime'); $this->documentation = Piwik::translate('VisitTime_WidgetLocalTimeDocumentation', array('', '')); $this->constantRowsCount = true; - $this->order = 20; - $this->widgetTitle = 'VisitTime_WidgetLocalTime'; + $this->order = 15; + + $this->subcategoryId = 'VisitTime_SubmenuTimes'; } public function configureView(ViewDataTable $view) @@ -42,10 +44,12 @@ class GetVisitInformationPerLocalTime extends Base if ($view->isViewDataTableId(Graph::ID)) { $view->config->max_graph_elements = false; } + } - // add the visits by day of week as a related report, if the current period is not 'day' - if (Common::getRequestVar('period', 'day') != 'day') { - $view->config->addRelatedReport('VisitTime.getByDayOfWeek', Piwik::translate('VisitTime_VisitsByDayOfWeek')); - } + public function getRelatedReports() + { + return array( + Reports::factory('VisitTime', 'getByDayOfWeek') + ); } } diff --git a/plugins/VisitTime/Reports/GetVisitInformationPerServerTime.php b/plugins/VisitTime/Reports/GetVisitInformationPerServerTime.php index ce213fb211..871f760046 100644 --- a/plugins/VisitTime/Reports/GetVisitInformationPerServerTime.php +++ b/plugins/VisitTime/Reports/GetVisitInformationPerServerTime.php @@ -22,12 +22,13 @@ class GetVisitInformationPerServerTime extends Base { parent::init(); $this->dimension = new ServerTime(); - $this->name = Piwik::translate('VisitTime_WidgetServerTime'); + $this->name = Piwik::translate('VisitTime_ServerTime'); $this->documentation = Piwik::translate('VisitTime_WidgetServerTimeDocumentation', array('', '')); $this->constantRowsCount = true; $this->hasGoalMetrics = true; - $this->order = 15; - $this->widgetTitle = 'VisitTime_WidgetServerTime'; + $this->order = 20; + + $this->subcategoryId = 'VisitTime_SubmenuTimes'; } public function configureView(ViewDataTable $view) diff --git a/plugins/VisitTime/templates/index.twig b/plugins/VisitTime/templates/index.twig deleted file mode 100644 index 688cde0338..0000000000 --- a/plugins/VisitTime/templates/index.twig +++ /dev/null @@ -1,13 +0,0 @@ -
    - -
    -

    {{ 'VisitTime_LocalTime'|translate }}

    - {{ dataTableVisitInformationPerLocalTime|raw }} -
    - -
    -

    {{ 'VisitTime_ServerTime'|translate }}

    - {{ dataTableVisitInformationPerServerTime|raw }} -
    - -
    diff --git a/plugins/VisitorInterest/Controller.php b/plugins/VisitorInterest/Controller.php deleted file mode 100644 index 8cb5200c4d..0000000000 --- a/plugins/VisitorInterest/Controller.php +++ /dev/null @@ -1,24 +0,0 @@ -dataTableNumberOfVisitsPerVisitDuration = $this->renderReport('getNumberOfVisitsPerVisitDuration'); - $view->dataTableNumberOfVisitsPerPage = $this->renderReport('getNumberOfVisitsPerPage'); - $view->dataTableNumberOfVisitsByVisitNum = $this->renderReport('getNumberOfVisitsByVisitCount'); - $view->dataTableNumberOfVisitsByDaysSinceLast = $this->renderReport('getNumberOfVisitsByDaysSinceLast'); - return $view->render(); - } -} \ No newline at end of file diff --git a/plugins/VisitorInterest/Menu.php b/plugins/VisitorInterest/Menu.php deleted file mode 100644 index 17de395000..0000000000 --- a/plugins/VisitorInterest/Menu.php +++ /dev/null @@ -1,20 +0,0 @@ -rename('General_Visitors', 'VisitFrequency_SubmenuFrequency', - 'General_Visitors', 'VisitorInterest_Engagement'); - } -} diff --git a/plugins/VisitorInterest/Reports/Base.php b/plugins/VisitorInterest/Reports/Base.php index fb3f0b4a42..3381a8e805 100644 --- a/plugins/VisitorInterest/Reports/Base.php +++ b/plugins/VisitorInterest/Reports/Base.php @@ -12,7 +12,8 @@ abstract class Base extends \Piwik\Plugin\Report { protected function init() { - $this->category = 'General_Visitors'; + $this->categoryId = 'General_Visitors'; + $this->subcategoryId = 'VisitorInterest_Engagement'; } } diff --git a/plugins/VisitorInterest/Reports/GetNumberOfVisitsByDaysSinceLast.php b/plugins/VisitorInterest/Reports/GetNumberOfVisitsByDaysSinceLast.php index fd935d47c6..b7b7302842 100644 --- a/plugins/VisitorInterest/Reports/GetNumberOfVisitsByDaysSinceLast.php +++ b/plugins/VisitorInterest/Reports/GetNumberOfVisitsByDaysSinceLast.php @@ -11,6 +11,8 @@ namespace Piwik\Plugins\VisitorInterest\Reports; use Piwik\Piwik; use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\VisitorInterest\Columns\VisitsByDaysSinceLastVisit; +use Piwik\Report\ReportWidgetFactory; +use Piwik\Widget\WidgetsList; class GetNumberOfVisitsByDaysSinceLast extends Base { @@ -26,7 +28,14 @@ class GetNumberOfVisitsByDaysSinceLast extends Base $this->processedMetrics = false; $this->constantRowsCount = true; $this->order = 30; - $this->widgetTitle = 'VisitorInterest_WidgetVisitsByDaysSinceLast'; + + $this->subcategoryId = 'VisitorInterest_Engagement'; + } + + public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory) + { + $widget = $factory->createWidget()->setName('VisitorInterest_WidgetVisitsByDaysSinceLast'); + $widgetsList->addWidgetConfig($widget); } public function configureView(ViewDataTable $view) diff --git a/plugins/VisitorInterest/Reports/GetNumberOfVisitsByVisitCount.php b/plugins/VisitorInterest/Reports/GetNumberOfVisitsByVisitCount.php index 74dbf69c14..d7c2a7b7e8 100644 --- a/plugins/VisitorInterest/Reports/GetNumberOfVisitsByVisitCount.php +++ b/plugins/VisitorInterest/Reports/GetNumberOfVisitsByVisitCount.php @@ -31,7 +31,6 @@ class GetNumberOfVisitsByVisitCount extends Base ); $this->constantRowsCount = true; $this->order = 25; - $this->widgetTitle = 'VisitorInterest_visitsByVisitCount'; } public function configureView(ViewDataTable $view) diff --git a/plugins/VisitorInterest/Reports/GetNumberOfVisitsPerPage.php b/plugins/VisitorInterest/Reports/GetNumberOfVisitsPerPage.php index de15ed5f5f..395c70da2b 100644 --- a/plugins/VisitorInterest/Reports/GetNumberOfVisitsPerPage.php +++ b/plugins/VisitorInterest/Reports/GetNumberOfVisitsPerPage.php @@ -13,6 +13,8 @@ use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\CoreVisualizations\Visualizations\Cloud; use Piwik\Plugins\CoreVisualizations\Visualizations\Graph; use Piwik\Plugins\VisitorInterest\Columns\PagesPerVisit; +use Piwik\Report\ReportWidgetFactory; +use Piwik\Widget\WidgetsList; class GetNumberOfVisitsPerPage extends Base { @@ -29,7 +31,13 @@ class GetNumberOfVisitsPerPage extends Base $this->processedMetrics = false; $this->constantRowsCount = true; $this->order = 20; - $this->widgetTitle = 'VisitorInterest_WidgetPages'; + } + + public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory) + { + $widgetsList->addWidgetConfig( + $factory->createWidget()->setName('VisitorInterest_VisitsPerNbOfPages') + ); } public function getDefaultTypeViewDataTable() diff --git a/plugins/VisitorInterest/Reports/GetNumberOfVisitsPerVisitDuration.php b/plugins/VisitorInterest/Reports/GetNumberOfVisitsPerVisitDuration.php index ead1849b7f..8ca31b560c 100644 --- a/plugins/VisitorInterest/Reports/GetNumberOfVisitsPerVisitDuration.php +++ b/plugins/VisitorInterest/Reports/GetNumberOfVisitsPerVisitDuration.php @@ -13,6 +13,8 @@ use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\CoreVisualizations\Visualizations\Cloud; use Piwik\Plugins\CoreVisualizations\Visualizations\Graph; use Piwik\Plugins\VisitorInterest\Columns\VisitDuration; +use Piwik\Report\ReportWidgetFactory; +use Piwik\Widget\WidgetsList; class GetNumberOfVisitsPerVisitDuration extends Base { @@ -29,7 +31,13 @@ class GetNumberOfVisitsPerVisitDuration extends Base $this->processedMetrics = false; $this->constantRowsCount = true; $this->order = 15; - $this->widgetTitle = 'VisitorInterest_WidgetLengths'; + } + + public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory) + { + $widgetsList->addWidgetConfig( + $factory->createWidget()->setName('VisitorInterest_VisitsPerDuration') + ); } public function getDefaultTypeViewDataTable() diff --git a/plugins/VisitorInterest/templates/index.twig b/plugins/VisitorInterest/templates/index.twig deleted file mode 100644 index 332289e106..0000000000 --- a/plugins/VisitorInterest/templates/index.twig +++ /dev/null @@ -1,21 +0,0 @@ -
    -
    -

    {{ 'VisitorInterest_VisitsPerDuration'|translate }}

    - {{ dataTableNumberOfVisitsPerVisitDuration|raw }} -
    -
    -

    {{ 'VisitorInterest_VisitsPerNbOfPages'|translate }}

    - {{ dataTableNumberOfVisitsPerPage|raw }} -
    -
    - -
    -
    -

    {{ 'VisitorInterest_visitsByVisitCount'|translate }}

    - {{ dataTableNumberOfVisitsByVisitNum|raw }} -
    -
    -

    {{ 'VisitorInterest_VisitsByDaysSinceLast'|translate }}

    - {{ dataTableNumberOfVisitsByDaysSinceLast|raw }} -
    -
    diff --git a/plugins/VisitsSummary/API.php b/plugins/VisitsSummary/API.php index b80c505fbb..c46bd93b7b 100644 --- a/plugins/VisitsSummary/API.php +++ b/plugins/VisitsSummary/API.php @@ -12,6 +12,7 @@ use Piwik\Archive; use Piwik\Metrics\Formatter; use Piwik\Piwik; use Piwik\Plugin\Report; +use Piwik\Plugin\Reports; use Piwik\SettingsPiwik; /** @@ -29,7 +30,7 @@ class API extends \Piwik\Plugin\API $requestedColumns = Piwik::getArrayFromApiParameter($columns); - $report = Report::factory("VisitsSummary", "get"); + $report = Reports::factory("VisitsSummary", "get"); $columns = $report->getMetricsRequiredForReport($this->getCoreColumns($period), $requestedColumns); $dataTable = $archive->getDataTableFromNumeric($columns); diff --git a/plugins/VisitsSummary/Controller.php b/plugins/VisitsSummary/Controller.php index 336ee26937..ca141b7ed8 100644 --- a/plugins/VisitsSummary/Controller.php +++ b/plugins/VisitsSummary/Controller.php @@ -12,8 +12,9 @@ use Piwik\API\Request; use Piwik\Common; use Piwik\DataTable; use Piwik\DataTable\Row; +use Piwik\FrontController; use Piwik\Piwik; -use Piwik\Plugins\Actions\API as APIActions; +use Piwik\Plugins\CoreVisualizations\Visualizations\Sparklines; use Piwik\Site; use Piwik\Translation\Translator; use Piwik\View; @@ -35,38 +36,32 @@ class Controller extends \Piwik\Plugin\Controller parent::__construct(); } - public function index() + /** + * @deprecated used to be a widgetized URL. There to not break widget URLs + */ + public function getSparklines() { - $view = new View('@VisitsSummary/index'); - $this->setPeriodVariablesView($view); - $view->graphEvolutionVisitsSummary = $this->getEvolutionGraph(array(), array('nb_visits'), 'getIndexGraph'); - $this->setSparklinesAndNumbers($view); - return $view->render(); - } + $_GET['forceView'] = '1'; + $_GET['viewDataTable'] = Sparklines::ID; - // sparkline.js:81 dataTable.trigger('reload', …); does not remove the old headline, - // so when updating this graph (such as when selecting a different metric) - // ONLY the graph should be returned - public function getIndexGraph() - { - return $this->getEvolutionGraph(array(), array(), __FUNCTION__); + return FrontController::getInstance()->fetchDispatch('VisitsSummary', 'get'); } - public function getSparklines() + /** + * @deprecated used to be a widgetized URL. There to not break widget URLs + */ + public function index() { - $view = new View('@VisitsSummary/getSparklines'); - $this->setPeriodVariablesView($view); - $this->setSparklinesAndNumbers($view); - return $view->render(); + $_GET['containerId'] = 'VisitOverviewWithGraph'; + + return FrontController::getInstance()->fetchDispatch('CoreHome', 'renderWidgetContainer'); } - public function getEvolutionGraph(array $columns = array(), array $defaultColumns = array(), $callingAction = __FUNCTION__) + public function getEvolutionGraph() { - if (empty($columns)) { - $columns = Common::getRequestVar('columns', false); - if (false !== $columns) { - $columns = Piwik::getArrayFromApiParameter($columns); - } + $columns = Common::getRequestVar('columns', false); + if (false !== $columns) { + $columns = Piwik::getArrayFromApiParameter($columns); } $documentation = $this->translator->translate('VisitsSummary_VisitsSummaryDocumentation') . '
    ' @@ -116,11 +111,11 @@ class Controller extends \Piwik\Plugin\Controller } // $callingAction may be specified to distinguish between // "VisitsSummary_WidgetLastVisits" and "VisitsSummary_WidgetOverviewGraph" - $view = $this->getLastUnitGraphAcrossPlugins($this->pluginName, $callingAction, $columns, + $view = $this->getLastUnitGraphAcrossPlugins($this->pluginName, __FUNCTION__, $columns, $selectableColumns, $documentation); - if (empty($view->config->columns_to_display) && !empty($defaultColumns)) { - $view->config->columns_to_display = $defaultColumns; + if (empty($view->config->columns_to_display)) { + $view->config->columns_to_display = array('nb_visits'); } return $this->renderView($view); @@ -137,87 +132,4 @@ class Controller extends \Piwik\Plugin\Controller return empty($result) ? new DataTable() : $result; } - - public static function getVisits() - { - $requestString = "method=VisitsSummary.getVisits" . - "&format=original" . - "&disable_generic_filters=1"; - $request = new Request($requestString); - return $request->process(); - } - - protected function setSparklinesAndNumbers($view) - { - $view->urlSparklineNbVisits = $this->getUrlSparkline('getEvolutionGraph', array('columns' => $view->displayUniqueVisitors ? array('nb_visits', 'nb_uniq_visitors') : array('nb_visits'))); - $view->urlSparklineNbUsers = $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('nb_users'))); - $view->urlSparklineNbPageviews = $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('nb_pageviews', 'nb_uniq_pageviews'))); - $view->urlSparklineNbDownloads = $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('nb_downloads', 'nb_uniq_downloads'))); - $view->urlSparklineNbOutlinks = $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('nb_outlinks', 'nb_uniq_outlinks'))); - $view->urlSparklineAvgVisitDuration = $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('avg_time_on_site'))); - $view->urlSparklineMaxActions = $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('max_actions'))); - $view->urlSparklineActionsPerVisit = $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('nb_actions_per_visit'))); - $view->urlSparklineBounceRate = $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('bounce_rate'))); - $view->urlSparklineAvgGenerationTime = $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('avg_time_generation'))); - - $idSite = Common::getRequestVar('idSite'); - $displaySiteSearch = Site::isSiteSearchEnabledFor($idSite); - if ($displaySiteSearch) { - $view->urlSparklineNbSearches = $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('nb_searches', 'nb_keywords'))); - } - $view->displaySiteSearch = $displaySiteSearch; - - $dataTableVisit = self::getVisitsSummary(); - $dataRow = $dataTableVisit->getRowsCount() == 0 ? new Row() : $dataTableVisit->getFirstRow(); - $view->nbUniqVisitors = (int)$dataRow->getColumn('nb_uniq_visitors'); - $view->nbUsers = (int)$dataRow->getColumn('nb_users'); - $nbVisits = (int)$dataRow->getColumn('nb_visits'); - $view->nbVisits = $nbVisits; - - $view->averageVisitDuration = $dataRow->getColumn('avg_time_on_site'); - $view->bounceRate = $dataRow->getColumn('bounce_rate'); - $view->maxActions = (int)$dataRow->getColumn('max_actions'); - $view->nbActionsPerVisit = $dataRow->getColumn('nb_actions_per_visit'); - - if (Common::isActionsPluginEnabled()) { - $view->showActionsPluginReports = true; - - $dataTableActions = Request::processRequest("Actions.get", array( - 'idSite' => $idSite, - 'period' => Common::getRequestVar('period'), - 'date' => Common::getRequestVar('date'), - 'segment' => Request::getRawSegmentFromRequest() - ), $defaultParams = array()); - - $dataActionsRow = - $dataTableActions->getRowsCount() == 0 ? new Row() : $dataTableActions->getFirstRow(); - - $view->nbPageviews = (int)$dataActionsRow->getColumn('nb_pageviews'); - $view->nbUniquePageviews = (int)$dataActionsRow->getColumn('nb_uniq_pageviews'); - $view->nbDownloads = (int)$dataActionsRow->getColumn('nb_downloads'); - $view->nbUniqueDownloads = (int)$dataActionsRow->getColumn('nb_uniq_downloads'); - $view->nbOutlinks = (int)$dataActionsRow->getColumn('nb_outlinks'); - $view->nbUniqueOutlinks = (int)$dataActionsRow->getColumn('nb_uniq_outlinks'); - $view->averageGenerationTime = $dataActionsRow->getColumn('avg_time_generation'); - - if ($displaySiteSearch) { - $view->nbSearches = (int)$dataActionsRow->getColumn('nb_searches'); - $view->nbKeywords = (int)$dataActionsRow->getColumn('nb_keywords'); - } - - // backward compatibility: - // show actions if the finer metrics are not archived - $view->showOnlyActions = false; - if ($dataActionsRow->getColumn('nb_pageviews') - + $dataActionsRow->getColumn('nb_downloads') - + $dataActionsRow->getColumn('nb_outlinks') == 0 - && $dataRow->getColumn('nb_actions') > 0 - ) { - $view->showOnlyActions = true; - $view->nbActions = $dataRow->getColumn('nb_actions'); - $view->urlSparklineNbActions = $this->getUrlSparkline('getEvolutionGraph', array('columns' => array('nb_actions'))); - } - } - - } } diff --git a/plugins/VisitsSummary/Menu.php b/plugins/VisitsSummary/Menu.php deleted file mode 100644 index 1b87e46be9..0000000000 --- a/plugins/VisitsSummary/Menu.php +++ /dev/null @@ -1,20 +0,0 @@ -addVisitorsItem('', array('module' => 'VisitsSummary', 'action' => 'index'), 10); - $menu->addVisitorsItem('General_Overview', array('module' => 'VisitsSummary', 'action' => 'index'), 1); - } -} diff --git a/plugins/VisitsSummary/Reports/Get.php b/plugins/VisitsSummary/Reports/Get.php index 55696873be..7fb95d2950 100644 --- a/plugins/VisitsSummary/Reports/Get.php +++ b/plugins/VisitsSummary/Reports/Get.php @@ -8,11 +8,23 @@ */ namespace Piwik\Plugins\VisitsSummary\Reports; +use Piwik\Common; +use Piwik\Container\StaticContainer; +use Piwik\DataTable; use Piwik\DataTable\DataTableInterface; +use Piwik\Metrics\Formatter; use Piwik\Piwik; +use Piwik\Plugin\ViewDataTable; use Piwik\Plugins\CoreHome\Columns\Metrics\ActionsPerVisit; use Piwik\Plugins\CoreHome\Columns\Metrics\AverageTimeOnSite; use Piwik\Plugins\CoreHome\Columns\Metrics\BounceRate; +use Piwik\Plugins\CoreHome\Columns\UserId; +use Piwik\Plugins\CoreVisualizations\Visualizations\JqplotGraph\Evolution; +use Piwik\Plugins\CoreVisualizations\Visualizations\Sparklines; +use Piwik\Report\ReportWidgetFactory; +use Piwik\SettingsPiwik; +use Piwik\Site; +use Piwik\Widget\WidgetsList; class Get extends \Piwik\Plugin\Report { @@ -21,7 +33,7 @@ class Get extends \Piwik\Plugin\Report protected function init() { parent::init(); - $this->category = 'VisitsSummary_VisitsSummary'; + $this->categoryId = 'General_Visitors'; $this->name = Piwik::translate('VisitsSummary_VisitsSummary'); $this->documentation = ''; // TODO $this->processedMetrics = array( @@ -36,12 +48,145 @@ class Get extends \Piwik\Plugin\Report 'nb_actions', 'max_actions' ); + $this->subcategoryId = 'General_Overview'; // Used to process metrics, not displayed/used directly // 'sum_visit_length', // 'nb_visits_converted', $this->order = 1; } + public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory) + { + $widgetsList->addWidgetConfig( + $factory->createWidget() + ->setName('VisitsSummary_WidgetLastVisits') + ->forceViewDataTable(Evolution::ID) + ->setAction('getEvolutionGraph') + ->setOrder(5) + ); + + $widgetsList->addWidgetConfig( + $factory->createWidget() + ->setName('VisitsSummary_WidgetVisits') + ->forceViewDataTable(Sparklines::ID) + ->setOrder(10) + ); + } + + public function configureView(ViewDataTable $view) + { + if ($view->isViewDataTableId(Sparklines::ID)) { + /** @var Sparklines $view */ + $view->requestConfig->apiMethodToRequestDataTable = 'API.get'; + $this->addSparklineColumns($view); + $view->config->addTranslations($this->getSparklineTranslations()); + $view->config->filters[] = function (DataTable $table) use ($view) { + $firstRow = $table->getFirstRow(); + + if (($firstRow->getColumn('nb_pageviews') + + $firstRow->getColumn('nb_downloads') + + $firstRow->getColumn('nb_outlinks')) == 0 + && $firstRow->getColumn('nb_actions') > 0) { + $view->config->removeSparklineMetric(array('nb_downloads', 'nb_uniq_downloads')); + $view->config->removeSparklineMetric(array('nb_outlinks', 'nb_uniq_outlinks')); + $view->config->removeSparklineMetric(array('nb_pageviews', 'nb_uniq_pageviews')); + $view->config->removeSparklineMetric(array('nb_searches', 'nb_keywords')); + } else { + $view->config->removeSparklineMetric(array('nb_actions')); + } + + $nbUsers = $firstRow->getColumn('nb_users'); + if (!is_numeric($nbUsers) || 0 >= $nbUsers) { + $view->config->replaceSparklineMetric(array('nb_users'), ''); + } + + $avgGenerationTime = $firstRow->getColumn('avg_time_generation'); + if (false === $avgGenerationTime) { + // fix avgGenerationTime is not formatted if value is false + /** @var Formatter $formatter */ + $formatter = StaticContainer::get('Piwik\Metrics\Formatter'); + $avgGenerationTime = $formatter->getPrettyTimeFromSeconds($avgGenerationTime, true); + $firstRow->setColumn('avg_time_generation', $avgGenerationTime); + } + }; + } + } + + private function getSparklineTranslations() + { + $translations = array( + 'nb_actions' => 'NbActionsDescription', + 'nb_visits' => 'NbVisitsDescription', + 'nb_users' => 'NbUsersDescription', + 'nb_uniq_visitors' => 'NbUniqueVisitors', + 'avg_time_generation' => 'AverageGenerationTime', + 'avg_time_on_site' => 'AverageVisitDuration', + 'max_actions' => 'MaxNbActions', + 'nb_actions_per_visit' => 'NbActionsPerVisit', + 'nb_downloads' => 'NbDownloadsDescription', + 'nb_uniq_downloads' => 'NbUniqueDownloadsDescription', + 'nb_outlinks' => 'NbOutlinksDescription', + 'nb_uniq_outlinks' => 'NbUniqueOutlinksDescription', + 'nb_keywords' => 'NbKeywordsDescription', + 'nb_searches' => 'NbSearchesDescription', + 'nb_pageviews' => 'NbPageviewsDescription', + 'nb_uniq_pageviews' => 'NbUniquePageviewsDescription', + 'bounce_rate' => 'NbVisitsBounced', + ); + + foreach ($translations as $metric => $key) { + $translations[$metric] = Piwik::translate('VisitsSummary_' . $key); + } + + return $translations; + } + + private function addSparklineColumns(Sparklines $view) + { + $currentPeriod = Common::getRequestVar('period'); + $currentIdSite = Common::getRequestVar('idSite'); + $currentDate = Common::getRequestVar('date'); + $displayUniqueVisitors = SettingsPiwik::isUniqueVisitorsEnabled($currentPeriod); + + $isActionPluginEnabled = Common::isActionsPluginEnabled(); + + $view->config->addSparklineMetric($displayUniqueVisitors ? array('nb_visits', 'nb_uniq_visitors') : array('nb_visits'), 5); + + if ($isActionPluginEnabled) { + $view->config->addSparklineMetric(array('nb_actions'), 10); // either actions or pageviews will be displayed + $view->config->addSparklineMetric(array('nb_pageviews', 'nb_uniq_pageviews'), 20); + } else { + // make sure to still create a div on the right side for this, just leave it empty + $view->config->addPlaceholder(10); + } + + $userId = new UserId(); + if ($userId->isUsedInAtLeastOneSite($currentIdSite, $currentPeriod, $currentDate)) { + $view->config->addSparklineMetric(array('nb_users'), 30); + $view->config->addPlaceholder(31); + } + + $view->config->addSparklineMetric(array('avg_time_on_site'), 40); + + $idSite = Common::getRequestVar('idSite'); + if ($isActionPluginEnabled && Site::isSiteSearchEnabledFor($idSite)) { + $view->config->addSparklineMetric(array('nb_searches', 'nb_keywords'), 50); + } else { + // make sure to still create a div on the right side for this, just leave it empty + $view->config->addPlaceholder(50); + } + + $view->config->addSparklineMetric(array('bounce_rate'), 60); + + if ($isActionPluginEnabled) { + $view->config->addSparklineMetric(array('nb_downloads', 'nb_uniq_downloads'), 70); + $view->config->addSparklineMetric(array('nb_actions_per_visit'), 71); + $view->config->addSparklineMetric(array('nb_outlinks', 'nb_uniq_outlinks'), 72); + $view->config->addSparklineMetric(array('avg_time_generation'), 73); + $view->config->addSparklineMetric(array('max_actions'), 74); + } + } + public function getMetrics() { $metrics = parent::getMetrics(); diff --git a/plugins/VisitsSummary/Widgets.php b/plugins/VisitsSummary/Widgets.php deleted file mode 100644 index 5ec7eef56e..0000000000 --- a/plugins/VisitsSummary/Widgets.php +++ /dev/null @@ -1,22 +0,0 @@ -addWidget('VisitsSummary_WidgetLastVisits', 'getEvolutionGraph', array('columns' => array('nb_visits'))); - $this->addWidget('VisitsSummary_WidgetVisits', 'getSparklines'); - $this->addWidget('VisitsSummary_WidgetOverviewGraph', 'index'); - } - -} diff --git a/plugins/VisitsSummary/Widgets/Index.php b/plugins/VisitsSummary/Widgets/Index.php new file mode 100644 index 0000000000..1b39fad7c6 --- /dev/null +++ b/plugins/VisitsSummary/Widgets/Index.php @@ -0,0 +1,47 @@ +isEnabled(); + } + + public function getWidgetConfigs() + { + $report = Reports::factory('VisitsSummary', 'get'); + + $factory = new ReportWidgetFactory($report); + $widgets = array(); + + $list = new WidgetsList(); + $report->configureWidgets($list, $factory); + + foreach ($list->getWidgetConfigs() as $config) { + $config->setIsNotWidgetizable(); + $widgets[] = $config; + } + + return $widgets; + } +} diff --git a/plugins/VisitsSummary/lang/en.json b/plugins/VisitsSummary/lang/en.json index e4a46bc5ae..fc9d3c4777 100644 --- a/plugins/VisitsSummary/lang/en.json +++ b/plugins/VisitsSummary/lang/en.json @@ -1,22 +1,24 @@ { "VisitsSummary": { - "AverageGenerationTime": "%s average generation time", - "AverageVisitDuration": "%s average visit duration", + "AverageGenerationTime": "average generation time", + "AverageVisitDuration": "average visit duration", "GenerateQueries": "%s queries executed", "GenerateTime": "%s seconds to generate the page", - "MaxNbActions": "%s max actions in one visit", + "MaxNbActions": "max actions in one visit", "NbActionsDescription": "%s actions", - "NbActionsPerVisit": "%s actions (page views, downloads, outlinks and internal site searches) per visit", - "NbDownloadsDescription": "%s downloads", - "NbKeywordsDescription": "%s unique keywords", - "NbOutlinksDescription": "%s outlinks", - "NbPageviewsDescription": "%s pageviews", - "NbSearchesDescription": "%s total searches on your website", - "NbUniqueDownloadsDescription": "%s unique downloads", - "NbUniqueOutlinksDescription": "%s unique outlinks", - "NbUniquePageviewsDescription": "%s unique pageviews", - "NbUniqueVisitors": "%s unique visitors", - "NbVisitsBounced": "%s visits have bounced (left the website after one page)", + "NbActionsPerVisit": "actions (page views, downloads, outlinks and internal site searches) per visit", + "NbDownloadsDescription": "downloads", + "NbKeywordsDescription": "unique keywords", + "NbOutlinksDescription": "outlinks", + "NbPageviewsDescription": "pageviews", + "NbSearchesDescription": "total searches on your website", + "NbUniqueDownloadsDescription": "unique downloads", + "NbUniqueOutlinksDescription": "unique outlinks", + "NbUniquePageviewsDescription": "unique pageviews", + "NbUniqueVisitors": "unique visitors", + "NbUsersDescription": "users", + "NbVisitsDescription": "visits", + "NbVisitsBounced": "visits have bounced (left the website after one page)", "PluginDescription": "Reports general analytics metrics: visits, unique visitors, number of actions, bounce rate, etc.", "VisitsSummary": "Visits Summary", "VisitsSummaryDocumentation": "This is an overview of the visit evolution.", diff --git a/plugins/Widgetize/Controller.php b/plugins/Widgetize/Controller.php index 2e2e5bf8cb..cf6cb5114a 100644 --- a/plugins/Widgetize/Controller.php +++ b/plugins/Widgetize/Controller.php @@ -12,7 +12,6 @@ use Piwik\API\Request; use Piwik\Common; use Piwik\FrontController; use Piwik\View; -use Piwik\WidgetsList; /** * @@ -22,7 +21,6 @@ class Controller extends \Piwik\Plugin\Controller public function index() { $view = new View('@Widgetize/index'); - $view->availableWidgets = json_encode(WidgetsList::get()); $this->setGeneralVariablesView($view); return $view->render(); } @@ -35,7 +33,7 @@ class Controller extends \Piwik\Plugin\Controller $controllerName = Common::getRequestVar('moduleToWidgetize'); $actionName = Common::getRequestVar('actionToWidgetize'); - if($controllerName == 'API') { + if ($controllerName == 'API') { throw new \Exception("Widgetizing API requests is not supported for security reasons. Please change query parameter 'moduleToWidgetize'."); } diff --git a/plugins/Widgetize/templates/iframe.twig b/plugins/Widgetize/templates/iframe.twig index ce40bdb940..892960316a 100644 --- a/plugins/Widgetize/templates/iframe.twig +++ b/plugins/Widgetize/templates/iframe.twig @@ -17,6 +17,7 @@ +
    {{ content|raw }}
    diff --git a/plugins/Widgetize/templates/index.twig b/plugins/Widgetize/templates/index.twig index 49a2b5f6c1..a798723928 100644 --- a/plugins/Widgetize/templates/index.twig +++ b/plugins/Widgetize/templates/index.twig @@ -24,7 +24,6 @@ $('#widgetPreview').widgetPreview({ onPreviewLoaded: widgetized.callbackAddExportButtonsUnderWidget }); - broadcast.init(); }); diff --git a/plugins/Widgetize/tests/System/WidgetTest.php b/plugins/Widgetize/tests/System/WidgetTest.php index d2d6ec3260..2425ed3c9a 100644 --- a/plugins/Widgetize/tests/System/WidgetTest.php +++ b/plugins/Widgetize/tests/System/WidgetTest.php @@ -11,10 +11,11 @@ namespace Piwik\Plugins\Widgetize\tests\Integration; use Piwik\Container\StaticContainer; use Piwik\Http\ControllerResolver; use Piwik\Piwik; +use Piwik\Plugins\API; use Piwik\Plugins\Goals; use Piwik\Plugins\Widgetize\tests\Fixtures\WidgetizeFixture; use Piwik\Tests\Framework\TestCase\SystemTestCase; -use Piwik\WidgetsList; +use Piwik\Widget\WidgetsList; /** * @group Widgetize @@ -35,7 +36,7 @@ class WidgetTest extends SystemTestCase $_GET = array(); $_GET['idSite'] = self::$fixture->idSite; $_GET['period'] = 'year'; - $_GET['date'] = 'today'; + $_GET['date'] = '2013-01-23'; } public function tearDown() @@ -44,28 +45,35 @@ class WidgetTest extends SystemTestCase parent::tearDown(); } + public function test_allWidgetUniqueIdsAreActuallyUnique() + { + $uniqueIds = array(); + foreach (WidgetsList::get()->getWidgetConfigs() as $widget) { + $uniqueIds[] = $widget->getUniqueId(); + } + + $this->assertEquals(array_unique($uniqueIds), $uniqueIds); + } + public function test_AvailableWidgetListIsUpToDate() { - $namesOfWidgetsThatAreAPI = $this->getWidgetNames($this->getWidgetsThatAreAPI()); + $namesOfWidgetsThatAreAPI = array_map(function ($widget) { + return $widget['uniqueId']; + }, $this->getWidgetsThatAreAPICurrently()); Piwik::postEvent('Platform.initialized'); // userCountryMap defines it's Widgets via this event currently - $currentWidgetNames = array(); - foreach (WidgetsList::get() as $widgets) { - $currentWidgetNames = array_merge($this->getWidgetNames($widgets), $currentWidgetNames); - } + $widgets = API\API::getInstance()->getWidgetMetadata($_GET['idSite']); - $allWidgetNames = array_merge($namesOfWidgetsThatAreAPI, $currentWidgetNames); - $regressedWidgetNames = array_diff($allWidgetNames, $currentWidgetNames); + $currentUniqueIds = array(); + foreach ($widgets as $widget) { + $currentUniqueIds[] = $widget['uniqueId']; + } - $this->assertEmpty($regressedWidgetNames, 'The widgets list is no longer up to date. If you added, removed or renamed a widget please update `getAvailableWidgets()` otherwise you will need to fix it. Different names: ' . var_export($regressedWidgetNames, 1)); - } + $allWidgetNames = array_merge($namesOfWidgetsThatAreAPI, $currentUniqueIds); + $regressedWidgetIds = array_diff($allWidgetNames, $currentUniqueIds); - private function getWidgetNames($widgets) - { - return array_map(function ($widget) { - return $widget['name']; - }, $widgets); + $this->assertEmpty($regressedWidgetIds, 'The widgets list is no longer up to date. If you added or changed a widget please update `getWidgetsThatAreAPICurrently()`, if you removed a widget please add it to `getWidgetsThatAreDeprecatedButStillAPI()`. If the uniqueId changed you might need to create an update for Dashboards and Scheduled Reports! Different names: ' . var_export($regressedWidgetIds, 1)); } /** @@ -78,7 +86,8 @@ class WidgetTest extends SystemTestCase $params = $widget['parameters']; $parameters = array(); - $resolver = new ControllerResolver(StaticContainer::getContainer()); + /** @var ControllerResolver $resolver */ + $resolver = StaticContainer::get('Piwik\Http\ControllerResolver'); $controller = $resolver->getController($params['module'], $params['action'], $parameters); $this->assertNotEmpty($controller, $widget['name'] . ' is not renderable with following params: ' . json_encode($params) . '. This breaks the API, please make sure to keep the URL working'); @@ -86,11 +95,15 @@ class WidgetTest extends SystemTestCase public function availableWidgetsProvider() { - $widgets = $this->getWidgetsThatAreAPI(); - $data = array(); - foreach ($widgets as $widget) { + foreach ($this->getWidgetsThatAreAPICurrently() as $widget) { + if (!empty($widget)) { + $data[] = array($widget); + } + } + + foreach ($this->getWidgetsThatAreDeprecatedButStillAPI() as $widget) { if (!empty($widget)) { $data[] = array($widget); } @@ -99,746 +112,1163 @@ class WidgetTest extends SystemTestCase return $data; } + public function getWidgetsThatAreAPICurrently() + { + return array( + array ( + 'name' => 'Visits Overview (with graph)', + 'uniqueId' => 'widgetVisitOverviewWithGraph', + 'parameters' => + array ( + 'module' => 'CoreHome', + 'action' => 'renderWidgetContainer', + 'containerId' => 'VisitOverviewWithGraph', + ), + ),array ( + 'name' => 'Support Piwik!', + 'uniqueId' => 'widgetCoreHomegetDonateForm', + 'parameters' => + array ( + 'module' => 'CoreHome', + 'action' => 'getDonateForm', + ), + ),array ( + 'name' => 'Welcome!', + 'uniqueId' => 'widgetCoreHomegetPromoVideo', + 'parameters' => + array ( + 'module' => 'CoreHome', + 'action' => 'getPromoVideo', + ), + ),array ( + 'name' => 'Example Widget Name', + 'uniqueId' => 'widgetExamplePluginmyExampleWidget', + 'parameters' => + array ( + 'module' => 'ExamplePlugin', + 'action' => 'myExampleWidget', + ), + ),array ( + 'name' => 'Top Keywords for Page URL', + 'uniqueId' => 'widgetReferrersgetKeywordsForPage', + 'parameters' => + array ( + 'module' => 'Referrers', + 'action' => 'getKeywordsForPage', + ), + ),array ( + 'name' => 'Ecommerce Log', + 'uniqueId' => 'widgetEcommercegetEcommerceLog', + 'parameters' => + array ( + 'module' => 'Ecommerce', + 'action' => 'getEcommerceLog', + ), + ),array ( + 'name' => 'SEO Rankings', + 'uniqueId' => 'widgetSEOgetRank', + 'parameters' => + array ( + 'module' => 'SEO', + 'action' => 'getRank', + ), + ),array ( + 'name' => 'Piwik Changelog', + 'uniqueId' => 'widgetExampleRssWidgetrssChangelog', + 'parameters' => + array ( + 'module' => 'ExampleRssWidget', + 'action' => 'rssChangelog', + ), + ),array ( + 'name' => 'Piwik.org Blog', + 'uniqueId' => 'widgetExampleRssWidgetrssPiwik', + 'parameters' => + array ( + 'module' => 'ExampleRssWidget', + 'action' => 'rssPiwik', + ), + ),array ( + 'name' => 'Real-time Map', + 'uniqueId' => 'widgetUserCountryMaprealtimeMap', + 'parameters' => + array ( + 'module' => 'UserCountryMap', + 'action' => 'realtimeMap', + ), + ),array ( + 'name' => 'Visitor Map', + 'uniqueId' => 'widgetUserCountryMapvisitorMap', + 'parameters' => + array ( + 'module' => 'UserCountryMap', + 'action' => 'visitorMap', + ), + ),array ( + 'name' => 'Visitor profile', + 'uniqueId' => 'widgetLivegetVisitorProfilePopup', + 'parameters' => + array ( + 'module' => 'Live', + 'action' => 'getVisitorProfilePopup', + ), + ),array ( + 'name' => 'Visitors in Real-time', + 'uniqueId' => 'widgetLivewidget', + 'parameters' => + array ( + 'module' => 'Live', + 'action' => 'widget', + ), + ),array ( + 'name' => 'Insights Overview', + 'uniqueId' => 'widgetInsightsgetInsightsOverview', + 'parameters' => + array ( + 'module' => 'Insights', + 'action' => 'getInsightsOverview', + ), + ),array ( + 'name' => 'Movers and Shakers', + 'uniqueId' => 'widgetInsightsgetOverallMoversAndShakers', + 'parameters' => + array ( + 'module' => 'Insights', + 'action' => 'getOverallMoversAndShakers', + ), + ),array ( + 'name' => 'Real Time Visitor Count', + 'uniqueId' => 'widgetLivegetSimpleLastVisitCount', + 'parameters' => + array ( + 'module' => 'Live', + 'action' => 'getSimpleLastVisitCount', + ), + ),array ( + 'name' => 'Visits Over Time', + 'uniqueId' => 'widgetVisitsSummarygetEvolutionGraphforceView1viewDataTablegraphEvolution', + 'parameters' => + array ( + 'forceView' => 1, + 'viewDataTable' => 'graphEvolution', + 'module' => 'VisitsSummary', + 'action' => 'getEvolutionGraph', + ), + ),array ( + 'name' => 'Visits Overview', + 'uniqueId' => 'widgetVisitsSummarygetforceView1viewDataTablesparklines', + 'parameters' => + array ( + 'forceView' => 1, + 'viewDataTable' => 'sparklines', + 'module' => 'VisitsSummary', + 'action' => 'get', + ), + ),array ( + 'name' => 'Visitor Log', + 'uniqueId' => 'widgetLivegetLastVisitsDetailsforceView1viewDataTablePiwik%5CPlugins%5CLive%5CVisitorLogsmall1', + 'parameters' => + array ( + 'forceView' => 1, + 'viewDataTable' => 'Piwik\\Plugins\\Live\\VisitorLog', + 'module' => 'Live', + 'action' => 'getLastVisitsDetails', + 'small' => 1, + ), + ),array ( + 'name' => 'Custom Variables', + 'uniqueId' => 'widgetCustomVariablesgetCustomVariables', + 'parameters' => + array ( + 'module' => 'CustomVariables', + 'action' => 'getCustomVariables', + ), + ),array ( + 'name' => 'Device type', + 'uniqueId' => 'widgetDevicesDetectiongetType', + 'parameters' => + array ( + 'module' => 'DevicesDetection', + 'action' => 'getType', + ), + ),array ( + 'name' => 'Device model', + 'uniqueId' => 'widgetDevicesDetectiongetModel', + 'parameters' => + array ( + 'module' => 'DevicesDetection', + 'action' => 'getModel', + ), + ),array ( + 'name' => 'Device brand', + 'uniqueId' => 'widgetDevicesDetectiongetBrand', + 'parameters' => + array ( + 'module' => 'DevicesDetection', + 'action' => 'getBrand', + ), + ),array ( + 'name' => 'Screen Resolution', + 'uniqueId' => 'widgetResolutiongetResolution', + 'parameters' => + array ( + 'module' => 'Resolution', + 'action' => 'getResolution', + ), + ),array ( + 'name' => 'Operating System versions', + 'uniqueId' => 'widgetDevicesDetectiongetOsVersions', + 'parameters' => + array ( + 'module' => 'DevicesDetection', + 'action' => 'getOsVersions', + ), + ),array ( + 'name' => 'Browsers', + 'uniqueId' => 'widgetDevicesDetectiongetBrowsers', + 'parameters' => + array ( + 'module' => 'DevicesDetection', + 'action' => 'getBrowsers', + ), + ),array ( + 'name' => 'Browser version', + 'uniqueId' => 'widgetDevicesDetectiongetBrowserVersions', + 'parameters' => + array ( + 'module' => 'DevicesDetection', + 'action' => 'getBrowserVersions', + ), + ),array ( + 'name' => 'Configurations', + 'uniqueId' => 'widgetResolutiongetConfiguration', + 'parameters' => + array ( + 'module' => 'Resolution', + 'action' => 'getConfiguration', + ), + ),array ( + 'name' => 'Operating System families', + 'uniqueId' => 'widgetDevicesDetectiongetOsFamilies', + 'parameters' => + array ( + 'module' => 'DevicesDetection', + 'action' => 'getOsFamilies', + ), + ),array ( + 'name' => 'Browser engines', + 'uniqueId' => 'widgetDevicesDetectiongetBrowserEnginesviewDataTablegraphPie', + 'parameters' => + array ( + 'viewDataTable' => 'graphPie', + 'module' => 'DevicesDetection', + 'action' => 'getBrowserEngines', + ), + ),array ( + 'name' => 'Browser Plugins', + 'uniqueId' => 'widgetDevicePluginsgetPlugin', + 'parameters' => + array ( + 'module' => 'DevicePlugins', + 'action' => 'getPlugin', + ), + ),array ( + 'name' => 'Country', + 'uniqueId' => 'widgetUserCountrygetCountry', + 'parameters' => + array ( + 'module' => 'UserCountry', + 'action' => 'getCountry', + ), + ),array ( + 'name' => 'Region', + 'uniqueId' => 'widgetUserCountrygetRegion', + 'parameters' => + array ( + 'module' => 'UserCountry', + 'action' => 'getRegion', + ), + ),array ( + 'name' => 'Browser language', + 'uniqueId' => 'widgetUserLanguagegetLanguage', + 'parameters' => + array ( + 'module' => 'UserLanguage', + 'action' => 'getLanguage', + ), + ),array ( + 'name' => 'City', + 'uniqueId' => 'widgetUserCountrygetCity', + 'parameters' => + array ( + 'module' => 'UserCountry', + 'action' => 'getCity', + ), + ),array ( + 'name' => 'Language code', + 'uniqueId' => 'widgetUserLanguagegetLanguageCode', + 'parameters' => + array ( + 'module' => 'UserLanguage', + 'action' => 'getLanguageCode', + ), + ),array ( + 'name' => 'Visits per visit duration', + 'uniqueId' => 'widgetVisitorInterestgetNumberOfVisitsPerVisitDurationviewDataTablecloud', + 'parameters' => + array ( + 'viewDataTable' => 'cloud', + 'module' => 'VisitorInterest', + 'action' => 'getNumberOfVisitsPerVisitDuration', + ), + ),array ( + 'name' => 'Visits per number of pages', + 'uniqueId' => 'widgetVisitorInterestgetNumberOfVisitsPerPageviewDataTablecloud', + 'parameters' => + array ( + 'viewDataTable' => 'cloud', + 'module' => 'VisitorInterest', + 'action' => 'getNumberOfVisitsPerPage', + ), + ),array ( + 'name' => 'Visits by Visit Number', + 'uniqueId' => 'widgetVisitorInterestgetNumberOfVisitsByVisitCount', + 'parameters' => + array ( + 'module' => 'VisitorInterest', + 'action' => 'getNumberOfVisitsByVisitCount', + ), + ),array ( + 'name' => 'Visits by Days Since Last Visit', + 'uniqueId' => 'widgetVisitorInterestgetNumberOfVisitsByDaysSinceLast', + 'parameters' => + array ( + 'module' => 'VisitorInterest', + 'action' => 'getNumberOfVisitsByDaysSinceLast', + ), + ),array ( + 'name' => 'Returning Visits Over Time', + 'uniqueId' => 'widgetVisitFrequencygetEvolutionGraphforceView1viewDataTablegraphEvolution', + 'parameters' => + array ( + 'forceView' => 1, + 'viewDataTable' => 'graphEvolution', + 'module' => 'VisitFrequency', + 'action' => 'getEvolutionGraph', + ), + ),array ( + 'name' => 'Frequency Overview', + 'uniqueId' => 'widgetVisitFrequencygetforceView1viewDataTablesparklines', + 'parameters' => + array ( + 'forceView' => 1, + 'viewDataTable' => 'sparklines', + 'module' => 'VisitFrequency', + 'action' => 'get', + ), + ),array ( + 'name' => 'Visits per local time', + 'uniqueId' => 'widgetVisitTimegetVisitInformationPerLocalTimeviewDataTablegraphVerticalBar', + 'parameters' => + array ( + 'viewDataTable' => 'graphVerticalBar', + 'module' => 'VisitTime', + 'action' => 'getVisitInformationPerLocalTime', + ), + ),array ( + 'name' => 'Visits per server time', + 'uniqueId' => 'widgetVisitTimegetVisitInformationPerServerTimeviewDataTablegraphVerticalBar', + 'parameters' => + array ( + 'viewDataTable' => 'graphVerticalBar', + 'module' => 'VisitTime', + 'action' => 'getVisitInformationPerServerTime', + ), + ),array ( + 'name' => 'Visits by Day of Week', + 'uniqueId' => 'widgetVisitTimegetByDayOfWeekviewDataTablegraphVerticalBar', + 'parameters' => + array ( + 'viewDataTable' => 'graphVerticalBar', + 'module' => 'VisitTime', + 'action' => 'getByDayOfWeek', + ), + ),array ( + 'name' => 'Pages', + 'uniqueId' => 'widgetActionsgetPageUrls', + 'parameters' => + array ( + 'module' => 'Actions', + 'action' => 'getPageUrls', + ), + ),array ( + 'name' => 'Entry pages', + 'uniqueId' => 'widgetActionsgetEntryPageUrls', + 'parameters' => + array ( + 'module' => 'Actions', + 'action' => 'getEntryPageUrls', + ), + ),array ( + 'name' => 'Exit pages', + 'uniqueId' => 'widgetActionsgetExitPageUrls', + 'parameters' => + array ( + 'module' => 'Actions', + 'action' => 'getExitPageUrls', + ), + ),array ( + 'name' => 'Page titles', + 'uniqueId' => 'widgetActionsgetPageTitles', + 'parameters' => + array ( + 'module' => 'Actions', + 'action' => 'getPageTitles', + ), + ),array ( + 'name' => 'Site Search Keywords', + 'uniqueId' => 'widgetActionsgetSiteSearchKeywords', + 'parameters' => + array ( + 'module' => 'Actions', + 'action' => 'getSiteSearchKeywords', + ), + ),array ( + 'name' => 'Pages Following a Site Search', + 'uniqueId' => 'widgetActionsgetPageUrlsFollowingSiteSearch', + 'parameters' => + array ( + 'module' => 'Actions', + 'action' => 'getPageUrlsFollowingSiteSearch', + ), + ),array ( + 'name' => 'Search Keywords with No Results', + 'uniqueId' => 'widgetActionsgetSiteSearchNoResultKeywords', + 'parameters' => + array ( + 'module' => 'Actions', + 'action' => 'getSiteSearchNoResultKeywords', + ), + ),array ( + 'name' => 'Page Titles Following a Site Search', + 'uniqueId' => 'widgetActionsgetPageTitlesFollowingSiteSearch', + 'parameters' => + array ( + 'module' => 'Actions', + 'action' => 'getPageTitlesFollowingSiteSearch', + ), + ),array ( + 'name' => 'Search Categories', + 'uniqueId' => 'widgetActionsgetSiteSearchCategories', + 'parameters' => + array ( + 'module' => 'Actions', + 'action' => 'getSiteSearchCategories', + ), + ),array ( + 'name' => 'Outlinks', + 'uniqueId' => 'widgetActionsgetOutlinks', + 'parameters' => + array ( + 'module' => 'Actions', + 'action' => 'getOutlinks', + ), + ),array ( + 'name' => 'Downloads', + 'uniqueId' => 'widgetActionsgetDownloads', + 'parameters' => + array ( + 'module' => 'Actions', + 'action' => 'getDownloads', + ), + ),array ( + 'name' => 'Entry Page Titles', + 'uniqueId' => 'widgetActionsgetEntryPageTitles', + 'parameters' => + array ( + 'module' => 'Actions', + 'action' => 'getEntryPageTitles', + ), + ),array ( + 'name' => 'Exit page titles', + 'uniqueId' => 'widgetActionsgetExitPageTitles', + 'parameters' => + array ( + 'module' => 'Actions', + 'action' => 'getExitPageTitles', + ), + ),array ( + 'name' => 'Referrer Types', + 'uniqueId' => 'widgetReferrersgetReferrerTypeviewDataTabletableAllColumns', + 'parameters' => + array ( + 'viewDataTable' => 'tableAllColumns', + 'module' => 'Referrers', + 'action' => 'getReferrerType', + ), + ),array ( + 'name' => 'Referrers', + 'uniqueId' => 'widgetReferrersgetAllviewDataTabletableAllColumns', + 'parameters' => + array ( + 'viewDataTable' => 'tableAllColumns', + 'module' => 'Referrers', + 'action' => 'getAll', + ), + ),array ( + 'name' => 'Keywords', + 'uniqueId' => 'widgetReferrersgetKeywords', + 'parameters' => + array ( + 'module' => 'Referrers', + 'action' => 'getKeywords', + ), + ),array ( + 'name' => 'Search Engines', + 'uniqueId' => 'widgetReferrersgetSearchEngines', + 'parameters' => + array ( + 'module' => 'Referrers', + 'action' => 'getSearchEngines', + ), + ),array ( + 'name' => 'Websites', + 'uniqueId' => 'widgetReferrersgetWebsites', + 'parameters' => + array ( + 'module' => 'Referrers', + 'action' => 'getWebsites', + ), + ),array ( + 'name' => 'Social Networks', + 'uniqueId' => 'widgetReferrersgetSocialsviewDataTablegraphPie', + 'parameters' => + array ( + 'viewDataTable' => 'graphPie', + 'module' => 'Referrers', + 'action' => 'getSocials', + ), + ),array ( + 'name' => 'Campaigns', + 'uniqueId' => 'widgetReferrersgetCampaigns', + 'parameters' => + array ( + 'module' => 'Referrers', + 'action' => 'getCampaigns', + ), + ),array ( + 'name' => 'Overview', + 'uniqueId' => 'widgetGoalsOverview', + 'parameters' => + array ( + 'module' => 'CoreHome', + 'action' => 'renderWidgetContainer', + 'containerId' => 'GoalsOverview', + ), + ),array ( + 'name' => 'Overview', + 'uniqueId' => 'widgetEcommerceOverview', + 'parameters' => + array ( + 'module' => 'CoreHome', + 'action' => 'renderWidgetContainer', + 'containerId' => 'EcommerceOverview', + ), + ),array ( + 'name' => 'Download Software', + 'uniqueId' => 'widgetGoal_1', + 'parameters' => + array ( + 'module' => 'CoreHome', + 'action' => 'renderWidgetContainer', + 'containerId' => 'Goal_1', + ), + ),array ( + 'name' => 'Download Software2', + 'uniqueId' => 'widgetGoal_2', + 'parameters' => + array ( + 'module' => 'CoreHome', + 'action' => 'renderWidgetContainer', + 'containerId' => 'Goal_2', + ), + ),array ( + 'name' => 'Opens Contact Form', + 'uniqueId' => 'widgetGoal_3', + 'parameters' => + array ( + 'module' => 'CoreHome', + 'action' => 'renderWidgetContainer', + 'containerId' => 'Goal_3', + ), + ),array ( + 'name' => 'Visit Docs', + 'uniqueId' => 'widgetGoal_4', + 'parameters' => + array ( + 'module' => 'CoreHome', + 'action' => 'renderWidgetContainer', + 'containerId' => 'Goal_4', + ), + ),array ( + 'name' => 'Data tables', + 'uniqueId' => 'widgetExampleUIgetTemperatures', + 'parameters' => + array ( + 'module' => 'ExampleUI', + 'action' => 'getTemperatures', + ), + ),array ( + 'name' => 'Data tables', + 'uniqueId' => 'widgetExampleUIgetTemperaturesforceView1viewDataTablegraphVerticalBar', + 'parameters' => + array ( + 'forceView' => 1, + 'viewDataTable' => 'graphVerticalBar', + 'module' => 'ExampleUI', + 'action' => 'getTemperatures', + ), + ),array ( + 'name' => 'Treemap example', + 'uniqueId' => 'widgetExampleUIgetTemperaturesforceView1viewDataTableinfoviz-treemap', + 'parameters' => + array ( + 'forceView' => 1, + 'viewDataTable' => 'infoviz-treemap', + 'module' => 'ExampleUI', + 'action' => 'getTemperatures', + ), + ),array ( + 'name' => 'Temperatures evolution over time', + 'uniqueId' => 'widgetExampleUIgetTemperaturesEvolutionforceView1viewDataTablesparklines', + 'parameters' => + array ( + 'forceView' => 1, + 'viewDataTable' => 'sparklines', + 'module' => 'ExampleUI', + 'action' => 'getTemperaturesEvolution', + ), + ),array ( + 'name' => 'Evolution of server temperatures over the last few days', + 'uniqueId' => 'widgetExampleUIgetTemperaturesEvolutionforceView1viewDataTablegraphEvolutioncolumnsArray', + 'parameters' => + array ( + 'forceView' => 1, + 'viewDataTable' => 'graphEvolution', + 'module' => 'ExampleUI', + 'action' => 'getTemperaturesEvolution', + 'columns' => + array ( + 0 => 'server1', + 1 => 'server2', + ), + ), + ),array ( + 'name' => 'Pie graph', + 'uniqueId' => 'widgetExampleUIgetPlanetRatiosviewDataTablegraphPie', + 'parameters' => + array ( + 'viewDataTable' => 'graphPie', + 'module' => 'ExampleUI', + 'action' => 'getPlanetRatios', + ), + ),array ( + 'name' => 'Simple tag cloud', + 'uniqueId' => 'widgetExampleUIgetPlanetRatiosforceView1viewDataTablecloud', + 'parameters' => + array ( + 'forceView' => 1, + 'viewDataTable' => 'cloud', + 'module' => 'ExampleUI', + 'action' => 'getPlanetRatios', + ), + ),array ( + 'name' => 'Advanced tag cloud: with logos and links', + 'uniqueId' => 'widgetExampleUIgetPlanetRatiosWithLogosviewDataTablecloud', + 'parameters' => + array ( + 'viewDataTable' => 'cloud', + 'module' => 'ExampleUI', + 'action' => 'getPlanetRatiosWithLogos', + ) + ),array ( + 'name' => 'Continent', + 'uniqueId' => 'widgetUserCountrygetContinent', + 'parameters' => + array ( + 'module' => 'UserCountry', + 'action' => 'getContinent', + ), + ), array ( + 'name' => 'Event Categories', + 'uniqueId' => 'widgetEventsgetCategorysecondaryDimensioneventAction', + 'parameters' => + array ( + 'module' => 'Events', + 'action' => 'getCategory', + 'secondaryDimension' => 'eventAction', + ), + ), array ( + 'name' => 'Event Categories', + 'uniqueId' => 'widgetEventsgetCategorysecondaryDimensioneventAction', + 'parameters' => + array ( + 'module' => 'Events', + 'action' => 'getCategory', + 'secondaryDimension' => 'eventAction', + ), + ), array ( + 'name' => 'Event Actions', + 'uniqueId' => 'widgetEventsgetActionsecondaryDimensioneventName', + 'parameters' => + array ( + 'module' => 'Events', + 'action' => 'getAction', + 'secondaryDimension' => 'eventName', + ), + ), array ( + 'name' => 'Event Actions', + 'uniqueId' => 'widgetEventsgetActionsecondaryDimensioneventName', + 'parameters' => + array ( + 'module' => 'Events', + 'action' => 'getAction', + 'secondaryDimension' => 'eventName', + ), + ), array ( + 'name' => 'Event Actions', + 'uniqueId' => 'widgetEventsgetActionsecondaryDimensioneventName', + 'parameters' => + array ( + 'module' => 'Events', + 'action' => 'getAction', + 'secondaryDimension' => 'eventName', + ), + ), array ( + 'name' => 'Event Actions', + 'uniqueId' => 'widgetEventsgetActionsecondaryDimensioneventName', + 'parameters' => + array ( + 'module' => 'Events', + 'action' => 'getAction', + 'secondaryDimension' => 'eventName', + ), + ), array ( + 'name' => 'Event Names', + 'uniqueId' => 'widgetEventsgetNamesecondaryDimensioneventAction', + 'parameters' => + array ( + 'module' => 'Events', + 'action' => 'getName', + 'secondaryDimension' => 'eventAction', + ), + ), array ( + 'name' => 'Event Names', + 'uniqueId' => 'widgetEventsgetNamesecondaryDimensioneventAction', + 'parameters' => + array ( + 'module' => 'Events', + 'action' => 'getName', + 'secondaryDimension' => 'eventAction', + ), + ), array ( + 'name' => 'Event Names', + 'uniqueId' => 'widgetEventsgetNamesecondaryDimensioneventAction', + 'parameters' => + array ( + 'module' => 'Events', + 'action' => 'getName', + 'secondaryDimension' => 'eventAction', + ), + ), array ( + 'name' => 'Event Names', + 'uniqueId' => 'widgetEventsgetNamesecondaryDimensioneventAction', + 'parameters' => + array ( + 'module' => 'Events', + 'action' => 'getName', + 'secondaryDimension' => 'eventAction', + ), + ), array ( + 'name' => 'Event Categories', + 'uniqueId' => 'widgetEventsgetCategorysecondaryDimensioneventAction', + 'parameters' => + array ( + 'module' => 'Events', + 'action' => 'getCategory', + 'secondaryDimension' => 'eventAction', + ), + ), array ( + 'name' => 'Event Categories', + 'uniqueId' => 'widgetEventsgetCategorysecondaryDimensioneventAction', + 'parameters' => + array ( + 'module' => 'Events', + 'action' => 'getCategory', + 'secondaryDimension' => 'eventAction', + ), + ), array ( + 'name' => 'Content Piece', + 'uniqueId' => 'widgetContentsgetContentPieces', + 'parameters' => + array ( + 'module' => 'Contents', + 'action' => 'getContentPieces', + ), + ), array ( + 'name' => 'Content Piece', + 'uniqueId' => 'widgetContentsgetContentPieces', + 'parameters' => + array ( + 'module' => 'Contents', + 'action' => 'getContentPieces', + ), + ), array ( + 'name' => 'Content Name', + 'uniqueId' => 'widgetContentsgetContentNames', + 'parameters' => + array ( + 'module' => 'Contents', + 'action' => 'getContentNames', + ), + ), array ( + 'name' => 'Content Name', + 'uniqueId' => 'widgetContentsgetContentNames', + 'parameters' => + array ( + 'module' => 'Contents', + 'action' => 'getContentNames', + ), + ), array ( + 'name' => 'Content Name', + 'uniqueId' => 'widgetContentsgetContentNames', + 'parameters' => + array ( + 'module' => 'Contents', + 'action' => 'getContentNames', + ), + ), array ( + 'name' => 'Content Name', + 'uniqueId' => 'widgetContentsgetContentNames', + 'parameters' => + array ( + 'module' => 'Contents', + 'action' => 'getContentNames', + ), + ), array ( + 'name' => 'Content Piece', + 'uniqueId' => 'widgetContentsgetContentPieces', + 'parameters' => + array ( + 'module' => 'Contents', + 'action' => 'getContentPieces', + ), + ), array ( + 'name' => 'Content Piece', + 'uniqueId' => 'widgetContentsgetContentPieces', + 'parameters' => + array ( + 'module' => 'Contents', + 'action' => 'getContentPieces', + ), + ), array ( + 'name' => 'Product SKU', + 'uniqueId' => 'widgetGoalsgetItemsSku', + 'parameters' => + array ( + 'module' => 'Goals', + 'action' => 'getItemsSku', + ), + ), array ( + 'name' => 'Product SKU', + 'uniqueId' => 'widgetGoalsgetItemsSku', + 'parameters' => + array ( + 'module' => 'Goals', + 'action' => 'getItemsSku', + ), + ), array ( + 'name' => 'Product Category', + 'uniqueId' => 'widgetGoalsgetItemsCategory', + 'parameters' => + array ( + 'module' => 'Goals', + 'action' => 'getItemsCategory', + ), + ), + ); + } + /** * This is a list of all widgets that we consider API. We need to make sure the widgets will be still renderable * etc. * @return array */ - public function getWidgetsThatAreAPI() + public function getWidgetsThatAreDeprecatedButStillAPI() { - return array ( - array ( - 'name' => 'Visits by Server Time', - 'uniqueId' => 'widgetVisitTimegetVisitInformationPerServerTime', - 'parameters' => - array ( - 'module' => 'VisitTime', - 'action' => 'getVisitInformationPerServerTime', - ), - ), - array ( - 'name' => 'Visits by Local Time', - 'uniqueId' => 'widgetVisitTimegetVisitInformationPerLocalTime', - 'parameters' => - array ( - 'module' => 'VisitTime', - 'action' => 'getVisitInformationPerLocalTime', - ), - ), - array ( - 'name' => 'Visits by Day of Week', - 'uniqueId' => 'widgetVisitTimegetByDayOfWeek', - 'parameters' => - array ( - 'module' => 'VisitTime', - 'action' => 'getByDayOfWeek', - ), - ), - array ( - 'name' => 'Visits Over Time', - 'uniqueId' => 'widgetVisitsSummarygetEvolutionGraphcolumnsArray', - 'parameters' => - array ( - 'module' => 'VisitsSummary', - 'action' => 'getEvolutionGraph', - 'columns' => - array ( - 0 => 'nb_visits', - ), - ), - ), - array ( - 'name' => 'Visits Overview', - 'uniqueId' => 'widgetVisitsSummarygetSparklines', - 'parameters' => - array ( - 'module' => 'VisitsSummary', - 'action' => 'getSparklines', - ), - ), - array ( - 'name' => 'Visits Overview (with graph)', - 'uniqueId' => 'widgetVisitsSummaryindex', - 'parameters' => - array ( - 'module' => 'VisitsSummary', - 'action' => 'index', - ), - ), - array ( - 'name' => 'Real-time Map', - 'uniqueId' => 'widgetUserCountryMaprealtimeMap', - 'parameters' => - array ( - 'module' => 'UserCountryMap', - 'action' => 'realtimeMap', - ), - ), - array ( - 'name' => 'Visitor Log', - 'uniqueId' => 'widgetLivegetVisitorLogsmall1', - 'parameters' => - array ( - 'module' => 'Live', - 'action' => 'getVisitorLog', - 'small' => 1, - ), - ), - array ( - 'name' => 'Real Time Visitor Count', - 'uniqueId' => 'widgetLivegetSimpleLastVisitCount', - 'parameters' => - array ( - 'module' => 'Live', - 'action' => 'getSimpleLastVisitCount', - ), - ), - array ( - 'name' => 'Visitors in Real-time', - 'uniqueId' => 'widgetLivewidget', - 'parameters' => - array ( - 'module' => 'Live', - 'action' => 'widget', - ), - ), - array ( - 'name' => 'Visitor profile', - 'uniqueId' => 'widgetLivegetVisitorProfilePopup', - 'parameters' => - array ( - 'module' => 'Live', - 'action' => 'getVisitorProfilePopup', - ), - ), - array ( - 'name' => 'Visitor Map', - 'uniqueId' => 'widgetUserCountryMapvisitorMap', - 'parameters' => - array ( - 'module' => 'UserCountryMap', - 'action' => 'visitorMap', - ), - ), - array ( - 'name' => 'Visitor Location (Country)', - 'uniqueId' => 'widgetUserCountrygetCountry', - 'parameters' => - array ( - 'module' => 'UserCountry', - 'action' => 'getCountry', - ), - ), - array ( - 'name' => 'Visitor Location (Continent)', - 'uniqueId' => 'widgetUserCountrygetContinent', - 'parameters' => - array ( - 'module' => 'UserCountry', - 'action' => 'getContinent', - ), - ), - array ( - 'name' => 'Visitor Location (Region)', - 'uniqueId' => 'widgetUserCountrygetRegion', - 'parameters' => - array ( - 'module' => 'UserCountry', - 'action' => 'getRegion', - ), - ), - array ( - 'name' => 'Visitor Location (City)', - 'uniqueId' => 'widgetUserCountrygetCity', - 'parameters' => - array ( - 'module' => 'UserCountry', - 'action' => 'getCity', - ), - ), - array ( - 'name' => 'Custom Variables', - 'uniqueId' => 'widgetCustomVariablesgetCustomVariables', - 'parameters' => - array ( - 'module' => 'CustomVariables', - 'action' => 'getCustomVariables', - ), - ), - array ( - 'name' => 'Length of Visits', - 'uniqueId' => 'widgetVisitorInterestgetNumberOfVisitsPerVisitDuration', - 'parameters' => - array ( - 'module' => 'VisitorInterest', - 'action' => 'getNumberOfVisitsPerVisitDuration', - ), - ), - array ( - 'name' => 'Pages per Visit', - 'uniqueId' => 'widgetVisitorInterestgetNumberOfVisitsPerPage', - 'parameters' => - array ( - 'module' => 'VisitorInterest', - 'action' => 'getNumberOfVisitsPerPage', - ), - ), - array ( - 'name' => 'Visits by Visit Number', - 'uniqueId' => 'widgetVisitorInterestgetNumberOfVisitsByVisitCount', - 'parameters' => - array ( - 'module' => 'VisitorInterest', - 'action' => 'getNumberOfVisitsByVisitCount', - ), - ), - array ( - 'name' => 'Visits by Days Since Last Visit', - 'uniqueId' => 'widgetVisitorInterestgetNumberOfVisitsByDaysSinceLast', - 'parameters' => - array ( - 'module' => 'VisitorInterest', - 'action' => 'getNumberOfVisitsByDaysSinceLast', - ), - ), - array ( - 'name' => 'Frequency Overview', - 'uniqueId' => 'widgetVisitFrequencygetSparklines', - 'parameters' => - array ( - 'module' => 'VisitFrequency', - 'action' => 'getSparklines', - ), - ), - array ( - 'name' => 'Returning Visits Over Time', - 'uniqueId' => 'widgetVisitFrequencygetEvolutionGraphcolumnsArray', - 'parameters' => - array ( - 'module' => 'VisitFrequency', - 'action' => 'getEvolutionGraph', - 'columns' => - array ( - 0 => 'nb_visits_returning', - ), - ), - ), - array ( - 'name' => 'Screen Resolution', - 'uniqueId' => 'widgetResolutiongetResolution', - 'parameters' => - array ( - 'module' => 'Resolution', - 'action' => 'getResolution', - ), - ), - array ( - 'name' => 'Browser Plugins', - 'uniqueId' => 'widgetDevicePluginsgetPlugin', - 'parameters' => - array ( - 'module' => 'DevicePlugins', - 'action' => 'getPlugin', - ), - ), - array ( - 'name' => 'Visitor Configuration', - 'uniqueId' => 'widgetResolutiongetConfiguration', - 'parameters' => - array ( - 'module' => 'Resolution', - 'action' => 'getConfiguration', - ), - ), - array ( - 'name' => 'Browser language', - 'uniqueId' => 'widgetUserLanguagegetLanguage', - 'parameters' => - array ( - 'module' => 'UserLanguage', - 'action' => 'getLanguage', - ), - ), - array ( - 'name' => 'Language code', - 'uniqueId' => 'widgetUserLanguagegetLanguageCode', - 'parameters' => - array ( - 'module' => 'UserLanguage', - 'action' => 'getLanguageCode', - ), - ), - array ( - 'name' => 'Device type', - 'uniqueId' => 'widgetDevicesDetectiongetType', - 'parameters' => - array ( - 'module' => 'DevicesDetection', - 'action' => 'getType', - ), - ), - array ( - 'name' => 'Device brand', - 'uniqueId' => 'widgetDevicesDetectiongetBrand', - 'parameters' => - array ( - 'module' => 'DevicesDetection', - 'action' => 'getBrand', - ), - ), - array ( - 'name' => 'Visitor Browser', - 'uniqueId' => 'widgetDevicesDetectiongetBrowsers', - 'parameters' => - array ( - 'module' => 'DevicesDetection', - 'action' => 'getBrowsers', - ), - ), - array ( - 'name' => 'Device model', - 'uniqueId' => 'widgetDevicesDetectiongetModel', - 'parameters' => - array ( - 'module' => 'DevicesDetection', - 'action' => 'getModel', - ), - ), - array ( - 'name' => 'Browser version', - 'uniqueId' => 'widgetDevicesDetectiongetBrowserVersions', - 'parameters' => - array ( - 'module' => 'DevicesDetection', - 'action' => 'getBrowserVersions', - ), - ), - array ( - 'name' => 'Operating System families', - 'uniqueId' => 'widgetDevicesDetectiongetOsFamilies', - 'parameters' => - array ( - 'module' => 'DevicesDetection', - 'action' => 'getOsFamilies', - ), - ), - array ( - 'name' => 'Operating System versions', - 'uniqueId' => 'widgetDevicesDetectiongetOsVersions', - 'parameters' => - array ( - 'module' => 'DevicesDetection', - 'action' => 'getOsVersions', - ), - ), - array ( - 'name' => 'Browser engines', - 'uniqueId' => 'widgetDevicesDetectiongetBrowserEngines', - 'parameters' => - array ( - 'module' => 'DevicesDetection', - 'action' => 'getBrowserEngines', - ), - ), - array ( - 'name' => 'Pages', - 'uniqueId' => 'widgetActionsgetPageUrls', - 'parameters' => - array ( - 'module' => 'Actions', - 'action' => 'getPageUrls', - ), - ), - array ( - 'name' => 'Entry Pages', - 'uniqueId' => 'widgetActionsgetEntryPageUrls', - 'parameters' => - array ( - 'module' => 'Actions', - 'action' => 'getEntryPageUrls', - ), - ), - array ( - 'name' => 'Exit Pages', - 'uniqueId' => 'widgetActionsgetExitPageUrls', - 'parameters' => - array ( - 'module' => 'Actions', - 'action' => 'getExitPageUrls', - ), - ), - array ( - 'name' => 'Page Titles', - 'uniqueId' => 'widgetActionsgetPageTitles', - 'parameters' => - array ( - 'module' => 'Actions', - 'action' => 'getPageTitles', - ), - ), - array ( - 'name' => 'Entry Page Titles', - 'uniqueId' => 'widgetActionsgetEntryPageTitles', - 'parameters' => - array ( - 'module' => 'Actions', - 'action' => 'getEntryPageTitles', - ), - ), - array ( - 'name' => 'Exit Page Titles', - 'uniqueId' => 'widgetActionsgetExitPageTitles', - 'parameters' => - array ( - 'module' => 'Actions', - 'action' => 'getExitPageTitles', - ), - ), - array ( - 'name' => 'Outlinks', - 'uniqueId' => 'widgetActionsgetOutlinks', - 'parameters' => - array ( - 'module' => 'Actions', - 'action' => 'getOutlinks', - ), - ), - array ( - 'name' => 'Downloads', - 'uniqueId' => 'widgetActionsgetDownloads', - 'parameters' => - array ( - 'module' => 'Actions', - 'action' => 'getDownloads', - ), - ), - array ( - 'name' => 'Content Name', - 'uniqueId' => 'widgetContentsgetContentNames', - 'parameters' => - array ( - 'module' => 'Contents', - 'action' => 'getContentNames', - ), - ), - array ( - 'name' => 'Content Piece', - 'uniqueId' => 'widgetContentsgetContentPieces', - 'parameters' => - array ( - 'module' => 'Contents', - 'action' => 'getContentPieces', - ), - ), - array ( - 'name' => 'Event Categories', - 'uniqueId' => 'widgetEventsgetCategorysecondaryDimensioneventAction', - 'parameters' => - array ( - 'module' => 'Events', - 'action' => 'getCategory', - 'secondaryDimension' => 'eventAction', - ), - ), - array ( - 'name' => 'Event Actions', - 'uniqueId' => 'widgetEventsgetActionsecondaryDimensioneventName', - 'parameters' => - array ( - 'module' => 'Events', - 'action' => 'getAction', - 'secondaryDimension' => 'eventName', - ), - ), - array ( - 'name' => 'Event Names', - 'uniqueId' => 'widgetEventsgetNamesecondaryDimensioneventAction', - 'parameters' => - array ( - 'module' => 'Events', - 'action' => 'getName', - 'secondaryDimension' => 'eventAction', - ), - ), - array ( - 'name' => 'Site Search Keywords', - 'uniqueId' => 'widgetActionsgetSiteSearchKeywords', - 'parameters' => - array ( - 'module' => 'Actions', - 'action' => 'getSiteSearchKeywords', - ), - ), - array ( - 'name' => 'Search Keywords with No Results', - 'uniqueId' => 'widgetActionsgetSiteSearchNoResultKeywords', - 'parameters' => - array ( - 'module' => 'Actions', - 'action' => 'getSiteSearchNoResultKeywords', - ), - ), - array ( - 'name' => 'Search Categories', - 'uniqueId' => 'widgetActionsgetSiteSearchCategories', - 'parameters' => - array ( - 'module' => 'Actions', - 'action' => 'getSiteSearchCategories', - ), - ), - array ( - 'name' => 'Pages Following a Site Search', - 'uniqueId' => 'widgetActionsgetPageUrlsFollowingSiteSearch', - 'parameters' => - array ( - 'module' => 'Actions', - 'action' => 'getPageUrlsFollowingSiteSearch', - ), - ), - array ( - 'name' => 'Page Titles Following a Site Search', - 'uniqueId' => 'widgetActionsgetPageTitlesFollowingSiteSearch', - 'parameters' => - array ( - 'module' => 'Actions', - 'action' => 'getPageTitlesFollowingSiteSearch', - ), - ), - array ( - 'name' => 'Overview', - 'uniqueId' => 'widgetReferrersgetReferrerType', - 'parameters' => - array ( - 'module' => 'Referrers', - 'action' => 'getReferrerType', - ), - ), - array ( - 'name' => 'All Referrers', - 'uniqueId' => 'widgetReferrersgetAll', - 'parameters' => - array ( - 'module' => 'Referrers', - 'action' => 'getAll', - ), - ), - array ( - 'name' => 'Keywords', - 'uniqueId' => 'widgetReferrersgetKeywords', - 'parameters' => - array ( - 'module' => 'Referrers', - 'action' => 'getKeywords', - ), - ), - array ( - 'name' => 'Referrer Websites', - 'uniqueId' => 'widgetReferrersgetWebsites', - 'parameters' => - array ( - 'module' => 'Referrers', - 'action' => 'getWebsites', - ), - ), - array ( - 'name' => 'Search Engines', - 'uniqueId' => 'widgetReferrersgetSearchEngines', - 'parameters' => - array ( - 'module' => 'Referrers', - 'action' => 'getSearchEngines', - ), - ), - array ( - 'name' => 'Campaigns', - 'uniqueId' => 'widgetReferrersgetCampaigns', - 'parameters' => - array ( - 'module' => 'Referrers', - 'action' => 'getCampaigns', - ), - ), - array ( - 'name' => 'List of social networks', - 'uniqueId' => 'widgetReferrersgetSocials', - 'parameters' => - array ( - 'module' => 'Referrers', - 'action' => 'getSocials', - ), - ), - array ( - 'name' => 'Goals Overview', - 'uniqueId' => 'widgetGoalswidgetGoalsOverview', - 'parameters' => - array ( - 'module' => 'Goals', - 'action' => 'widgetGoalsOverview', - ), - ), - array ( - 'name' => 'Download Software', - 'uniqueId' => 'widgetGoalswidgetGoalReportidGoal1', - 'parameters' => - array ( - 'module' => 'Goals', - 'action' => 'widgetGoalReport', - 'idGoal' => '1', - ), - ), - array ( - 'name' => 'Download Software2', - 'uniqueId' => 'widgetGoalswidgetGoalReportidGoal2', - 'parameters' => - array ( - 'module' => 'Goals', - 'action' => 'widgetGoalReport', - 'idGoal' => '2', - ), - ), - array ( - 'name' => 'Opens Contact Form', - 'uniqueId' => 'widgetGoalswidgetGoalReportidGoal3', - 'parameters' => - array ( - 'module' => 'Goals', - 'action' => 'widgetGoalReport', - 'idGoal' => '3', - ), - ), - array ( - 'name' => 'Visit Docs', - 'uniqueId' => 'widgetGoalswidgetGoalReportidGoal4', - 'parameters' => - array ( - 'module' => 'Goals', - 'action' => 'widgetGoalReport', - 'idGoal' => '4', - ), - ), - array ( - 'name' => 'Product SKU', - 'uniqueId' => 'widgetGoalsgetItemsSku', - 'parameters' => - array ( - 'module' => 'Goals', - 'action' => 'getItemsSku', - ), - ), - array ( - 'name' => 'Product Name', - 'uniqueId' => 'widgetGoalsgetItemsName', - 'parameters' => - array ( - 'module' => 'Goals', - 'action' => 'getItemsName', - ), - ), - array ( - 'name' => 'Product Category', - 'uniqueId' => 'widgetGoalsgetItemsCategory', - 'parameters' => - array ( - 'module' => 'Goals', - 'action' => 'getItemsCategory', - ), - ), - array ( - 'name' => 'Overview', - 'uniqueId' => 'widgetEcommercewidgetGoalReportidGoalecommerceOrder', - 'parameters' => - array ( - 'module' => 'Ecommerce', - 'action' => 'widgetGoalReport', - 'idGoal' => 'ecommerceOrder', - ), - ), - array ( - 'name' => 'Ecommerce Log', - 'uniqueId' => 'widgetEcommercegetEcommerceLog', - 'parameters' => - array ( - 'module' => 'Ecommerce', - 'action' => 'getEcommerceLog', - ), - ), - array ( - 'name' => 'Insights Overview', - 'uniqueId' => 'widgetInsightsgetInsightsOverview', - 'parameters' => - array ( - 'module' => 'Insights', - 'action' => 'getInsightsOverview', - ), - ), - array ( - 'name' => 'Movers and Shakers', - 'uniqueId' => 'widgetInsightsgetOverallMoversAndShakers', - 'parameters' => - array ( - 'module' => 'Insights', - 'action' => 'getOverallMoversAndShakers', - ), - ), - array ( - 'name' => 'Top Keywords for Page URL', - 'uniqueId' => 'widgetReferrersgetKeywordsForPage', - 'parameters' => - array ( - 'module' => 'Referrers', - 'action' => 'getKeywordsForPage', - ), - ), - array ( - 'name' => 'SEO Rankings', - 'uniqueId' => 'widgetSEOgetRank', - 'parameters' => - array ( - 'module' => 'SEO', - 'action' => 'getRank', - ), - ), - array ( - 'name' => 'Support Piwik!', - 'uniqueId' => 'widgetCoreHomegetDonateForm', - 'parameters' => - array ( - 'module' => 'CoreHome', - 'action' => 'getDonateForm', - ), - ), - array ( - 'name' => 'Welcome!', - 'uniqueId' => 'widgetCoreHomegetPromoVideo', - 'parameters' => - array ( - 'module' => 'CoreHome', - 'action' => 'getPromoVideo', - ), - ), - array ( - 'name' => 'Piwik.org Blog', - 'uniqueId' => 'widgetExampleRssWidgetrssPiwik', - 'parameters' => - array ( - 'module' => 'ExampleRssWidget', - 'action' => 'rssPiwik', - ), - ), - array ( - 'name' => 'Piwik Changelog', - 'uniqueId' => 'widgetExampleRssWidgetrssChangelog', - 'parameters' => - array ( - 'module' => 'ExampleRssWidget', - 'action' => 'rssChangelog', - ), - ), + return array( + array ( + 'name' => 'Visits per server time', + 'uniqueId' => 'widgetVisitTimegetVisitInformationPerServerTime', + 'parameters' => + array ( + 'module' => 'VisitTime', + 'action' => 'getVisitInformationPerServerTime', + ), + ), array ( + 'name' => 'Visits per local time', + 'uniqueId' => 'widgetVisitTimegetVisitInformationPerLocalTime', + 'parameters' => + array ( + 'module' => 'VisitTime', + 'action' => 'getVisitInformationPerLocalTime', + ), + ), array ( + 'name' => 'Visits by Day of Week', + 'uniqueId' => 'widgetVisitTimegetByDayOfWeek', + 'parameters' => + array ( + 'module' => 'VisitTime', + 'action' => 'getByDayOfWeek', + ), + ), array ( + 'name' => 'Visits Over Time', + 'uniqueId' => 'widgetVisitsSummarygetEvolutionGraphcolumnsArray', + 'parameters' => + array ( + 'module' => 'VisitsSummary', + 'action' => 'getEvolutionGraph', + 'columns' => + array ( + 0 => 'nb_visits', + ), + ), + ), array ( + 'name' => 'Visits Overview', + 'uniqueId' => 'widgetVisitsSummarygetSparklines', + 'parameters' => + array ( + 'module' => 'VisitsSummary', + 'action' => 'getSparklines', + ), + ), array ( + 'name' => 'Visits Overview (with graph)', + 'uniqueId' => 'widgetVisitsSummaryindex', + 'parameters' => + array ( + 'module' => 'VisitsSummary', + 'action' => 'index', + ), + ), array ( + 'name' => 'Visitor Log', + 'uniqueId' => 'widgetLivegetVisitorLogsmall1', + 'parameters' => + array ( + 'module' => 'Live', + 'action' => 'getVisitorLog', + 'small' => 1, + ), + ), array ( + 'name' => 'Continent', + 'uniqueId' => 'widgetUserCountrygetContinent', + 'parameters' => + array ( + 'module' => 'UserCountry', + 'action' => 'getContinent', + ), + ), array ( + 'name' => 'Visits per visit duration', + 'uniqueId' => 'widgetVisitorInterestgetNumberOfVisitsPerVisitDuration', + 'parameters' => + array ( + 'module' => 'VisitorInterest', + 'action' => 'getNumberOfVisitsPerVisitDuration', + ), + ), array ( + 'name' => 'Pages per Visit', + 'uniqueId' => 'widgetVisitorInterestgetNumberOfVisitsPerPage', + 'parameters' => + array ( + 'module' => 'VisitorInterest', + 'action' => 'getNumberOfVisitsPerPage', + ), + ), array ( + 'name' => 'Frequency Overview', + 'uniqueId' => 'widgetVisitFrequencygetSparklines', + 'parameters' => + array ( + 'module' => 'VisitFrequency', + 'action' => 'getSparklines', + ), + ), array ( + 'name' => 'Returning Visits Over Time', + 'uniqueId' => 'widgetVisitFrequencygetEvolutionGraphcolumnsArray', + 'parameters' => + array ( + 'module' => 'VisitFrequency', + 'action' => 'getEvolutionGraph', + 'columns' => + array ( + 0 => 'nb_visits_returning', + ), + ), + ), array ( + 'name' => 'Browser engines', + 'uniqueId' => 'widgetDevicesDetectiongetBrowserEngines', + 'parameters' => + array ( + 'module' => 'DevicesDetection', + 'action' => 'getBrowserEngines', + ), + ), array ( + 'name' => 'Content Name', + 'uniqueId' => 'widgetContentsgetContentNames', + 'parameters' => + array ( + 'module' => 'Contents', + 'action' => 'getContentNames', + ), + ), array ( + 'name' => 'Content Piece', + 'uniqueId' => 'widgetContentsgetContentPieces', + 'parameters' => + array ( + 'module' => 'Contents', + 'action' => 'getContentPieces', + ), + ), array ( + 'name' => 'Event Categories', + 'uniqueId' => 'widgetEventsgetCategorysecondaryDimensioneventAction', + 'parameters' => + array ( + 'module' => 'Events', + 'action' => 'getCategory', + 'secondaryDimension' => 'eventAction', + ), + ), array ( + 'name' => 'Event Actions', + 'uniqueId' => 'widgetEventsgetActionsecondaryDimensioneventName', + 'parameters' => + array ( + 'module' => 'Events', + 'action' => 'getAction', + 'secondaryDimension' => 'eventName', + ), + ), array ( + 'name' => 'Event Names', + 'uniqueId' => 'widgetEventsgetNamesecondaryDimensioneventAction', + 'parameters' => + array ( + 'module' => 'Events', + 'action' => 'getName', + 'secondaryDimension' => 'eventAction', + ), + ), array ( + 'name' => 'Overview', + 'uniqueId' => 'widgetReferrersgetReferrerType', + 'parameters' => + array ( + 'module' => 'Referrers', + 'action' => 'getReferrerType', + ), + ), array ( + 'name' => 'All Referrers', + 'uniqueId' => 'widgetReferrersgetAll', + 'parameters' => + array ( + 'module' => 'Referrers', + 'action' => 'getAll', + ), + ), array ( + 'name' => 'List of social networks', + 'uniqueId' => 'widgetReferrersgetSocials', + 'parameters' => + array ( + 'module' => 'Referrers', + 'action' => 'getSocials', + ), + ), array ( + 'name' => 'Goals Overview', + 'uniqueId' => 'widgetGoalswidgetGoalsOverview', + 'parameters' => + array ( + 'module' => 'Goals', + 'action' => 'widgetGoalsOverview', + ), + ), array ( + 'name' => 'Download Software', + 'uniqueId' => 'widgetGoalswidgetGoalReportidGoal1', + 'parameters' => + array ( + 'module' => 'Goals', + 'action' => 'widgetGoalReport', + 'idGoal' => '1', + ), + ), array ( + 'name' => 'Download Software2', + 'uniqueId' => 'widgetGoalswidgetGoalReportidGoal2', + 'parameters' => + array ( + 'module' => 'Goals', + 'action' => 'widgetGoalReport', + 'idGoal' => '2', + ), + ), array ( + 'name' => 'Opens Contact Form', + 'uniqueId' => 'widgetGoalswidgetGoalReportidGoal3', + 'parameters' => + array ( + 'module' => 'Goals', + 'action' => 'widgetGoalReport', + 'idGoal' => '3', + ), + ), array ( + 'name' => 'Visit Docs', + 'uniqueId' => 'widgetGoalswidgetGoalReportidGoal4', + 'parameters' => + array ( + 'module' => 'Goals', + 'action' => 'widgetGoalReport', + 'idGoal' => '4', + ), + ), array ( + 'name' => 'Product SKU', + 'uniqueId' => 'widgetGoalsgetItemsSku', + 'parameters' => + array ( + 'module' => 'Goals', + 'action' => 'getItemsSku', + ), + ), array ( + 'name' => 'Product Name', + 'uniqueId' => 'widgetGoalsgetItemsName', + 'parameters' => + array ( + 'module' => 'Goals', + 'action' => 'getItemsName', + ), + ), array ( + 'name' => 'Product Category', + 'uniqueId' => 'widgetGoalsgetItemsCategory', + 'parameters' => + array ( + 'module' => 'Goals', + 'action' => 'getItemsCategory', + ), + ), array ( + 'name' => 'Overview', + 'uniqueId' => 'widgetEcommercewidgetGoalReportidGoalecommerceOrder', + 'parameters' => + array ( + 'module' => 'Ecommerce', + 'action' => 'widgetGoalReport', + 'idGoal' => 'ecommerceOrder', + ), + ) ); } } -WidgetTest::$fixture = new WidgetizeFixture(); \ No newline at end of file +WidgetTest::$fixture = new WidgetizeFixture(); diff --git a/plugins/ZenMode/ZenMode.php b/plugins/ZenMode/ZenMode.php index bbacb157c3..eee60c4603 100644 --- a/plugins/ZenMode/ZenMode.php +++ b/plugins/ZenMode/ZenMode.php @@ -40,6 +40,7 @@ class ZenMode extends \Piwik\Plugin { $jsFiles[] = "plugins/ZenMode/javascripts/zen-mode.js"; $jsFiles[] = "plugins/ZenMode/angularjs/quick-access/quick-access.directive.js"; + $jsFiles[] = "plugins/ZenMode/angularjs/zen-mode/zen-mode-disabler.js"; $jsFiles[] = "plugins/ZenMode/angularjs/zen-mode/zen-mode-switcher.directive.js"; } diff --git a/plugins/ZenMode/angularjs/zen-mode/zen-mode-disabler.js b/plugins/ZenMode/angularjs/zen-mode/zen-mode-disabler.js new file mode 100644 index 0000000000..420020b75f --- /dev/null +++ b/plugins/ZenMode/angularjs/zen-mode/zen-mode-disabler.js @@ -0,0 +1,35 @@ +/*! + * Piwik - free/libre analytics platform + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + */ + +/** + * Usage: + *
    ...
    + * Will toggle the zen mode on click on this element. + */ +(function () { + angular.module('piwikApp').directive('piwikReportingMenu', piwikZenModeSwitcher); + + piwikZenModeSwitcher.$inject = ['$rootElement', '$filter']; + + function piwikZenModeSwitcher($rootElement, $filter) { + + return { + restrict: 'A', + compile: function (element, attrs) { + + element.find('.Menu--dashboard').prepend( + '' + + '' + + ''); + + return function () { + }; + } + }; + + } +})(); \ No newline at end of file diff --git a/plugins/ZenMode/javascripts/zen-mode.js b/plugins/ZenMode/javascripts/zen-mode.js index bc2a793942..e4e163db8b 100644 --- a/plugins/ZenMode/javascripts/zen-mode.js +++ b/plugins/ZenMode/javascripts/zen-mode.js @@ -19,13 +19,6 @@ $(document).ready(function () { piwikHelper.compileAngularComponents(addedElement); - addedElement = $('.Menu--dashboard').prepend( - '' - + '' - + ''); - - piwikHelper.compileAngularComponents(addedElement); - angular.element(document).injector().invoke(handleZenMode); function handleZenMode ($rootElement, $cookies) { @@ -77,7 +70,7 @@ $(document).ready(function () { function isDashboard() { - return !!$('.Menu--dashboard').length; + return !!$('[piwik-reporting-menu]').length; } function initMenu () { @@ -98,7 +91,6 @@ $(document).ready(function () { $('#Searchmenu').off('keydown focus', '.quick-access input', showQuickAccessMenu); $('#Searchmenu').off('blur', '.quick-access input', hideQuickAccessMenu); - menu.prototype.adaptSubMenuHeight(); } function overMainLI () { diff --git a/tests/PHPUnit/Fixtures/OmniFixture.php b/tests/PHPUnit/Fixtures/OmniFixture.php index 123e214bd3..dd680e9085 100644 --- a/tests/PHPUnit/Fixtures/OmniFixture.php +++ b/tests/PHPUnit/Fixtures/OmniFixture.php @@ -73,12 +73,15 @@ class OmniFixture extends Fixture } } - $this->now = $this->fixtures['Piwik\\Tests\\Fixtures\\ManySitesImportedLogsWithXssAttempts']->now; - // make sure ManySitesImportedLogsWithXssAttempts is the first fixture - $fixture = $this->fixtures['Piwik\\Tests\\Fixtures\\ManySitesImportedLogsWithXssAttempts']; - unset($this->fixtures['Piwik\\Tests\\Fixtures\\ManySitesImportedLogsWithXssAttempts']); - $this->fixtures = array_merge(array('Piwik\\Tests\\Fixtures\\ManySitesImportedLogsWithXssAttempts' => $fixture), $this->fixtures); + if (!empty($this->fixtures['Piwik\\Tests\\Fixtures\\ManySitesImportedLogsWithXssAttempts'])) { + $this->now = $this->fixtures['Piwik\\Tests\\Fixtures\\ManySitesImportedLogsWithXssAttempts']->now; + + // make sure ManySitesImportedLogsWithXssAttempts is the first fixture + $fixture = $this->fixtures['Piwik\\Tests\\Fixtures\\ManySitesImportedLogsWithXssAttempts']; + unset($this->fixtures['Piwik\\Tests\\Fixtures\\ManySitesImportedLogsWithXssAttempts']); + $this->fixtures = array_merge(array('Piwik\\Tests\\Fixtures\\ManySitesImportedLogsWithXssAttempts' => $fixture), $this->fixtures); + } } private function adjustDateTime($dateTime, $adjustToDate) diff --git a/tests/PHPUnit/Fixtures/UITestFixture.php b/tests/PHPUnit/Fixtures/UITestFixture.php index eb35b24114..34c63a22e9 100644 --- a/tests/PHPUnit/Fixtures/UITestFixture.php +++ b/tests/PHPUnit/Fixtures/UITestFixture.php @@ -8,6 +8,7 @@ namespace Piwik\Tests\Fixtures; use Exception; +use Piwik\API\Request; use Piwik\AssetManager; use Piwik\Access; use Piwik\Common; @@ -22,9 +23,6 @@ use Piwik\Plugins\UserCountry\LocationProvider; use Piwik\Plugins\UsersManager\API as UsersManagerAPI; use Piwik\Plugins\SitesManager\API as SitesManagerAPI; use Piwik\Tests\Framework\Fixture; -use Piwik\WidgetsList; -use Piwik\Tests\Framework\OverrideLogin; -use Piwik\Tests\Framework\TestCase\SystemTestCase; /** * Fixture for UI tests. @@ -222,10 +220,10 @@ class UITestFixture extends SqlDump $_GET['token_auth'] = Fixture::getTokenAuth(); // collect widgets & sort them so widget order is not important - $allWidgets = array(); - foreach (WidgetsList::get() as $category => $widgets) { - $allWidgets = array_merge($allWidgets, $widgets); - } + $allWidgets = Request::processRequest('API.getWidgetMetadata', array( + 'idSite' => 1 + )); + usort($allWidgets, function ($lhs, $rhs) { return strcmp($lhs['uniqueId'], $rhs['uniqueId']); }); @@ -290,11 +288,12 @@ class UITestFixture extends SqlDump $dashboard = array( array( array( - 'uniqueId' => "widgetVisitsSummarygetEvolutionGraphcolumnsArray", + 'uniqueId' => "widgetVisitsSummarygetEvolutionGraphforceView1viewDataTablegraphEvolution", 'parameters' => array( 'module' => 'VisitsSummary', 'action' => 'getEvolutionGraph', - 'columns' => 'nb_visits' + 'forceView' => '1', + 'viewDataTable' => 'graphEvolution' ) ) ), diff --git a/tests/PHPUnit/Framework/Mock/Category/Categeories.php b/tests/PHPUnit/Framework/Mock/Category/Categeories.php new file mode 100644 index 0000000000..a7e7f0ce01 --- /dev/null +++ b/tests/PHPUnit/Framework/Mock/Category/Categeories.php @@ -0,0 +1,63 @@ +getId()] = $category; + } + + $this->categories = $cats; + } + + /** + * @param Subcategory[] $subcategories + */ + public function setSubcategories($subcategories) + { + $this->subcategories = $subcategories; + } + + public function getAllCategories() + { + if ($this->categories) { + return $this->categories; + } + + return parent::getAllCategories(); + } + + public function getAllSubcategories() + { + if ($this->subcategories) { + return $this->subcategories; + } + + return parent::getAllSubcategories(); + } + +} \ No newline at end of file diff --git a/tests/PHPUnit/Integration/Category/CategoryListTest.php b/tests/PHPUnit/Integration/Category/CategoryListTest.php new file mode 100644 index 0000000000..4c8cc4ec57 --- /dev/null +++ b/tests/PHPUnit/Integration/Category/CategoryListTest.php @@ -0,0 +1,133 @@ +assertSame(array( + 'General_Actions', + 'General_Visitors', + 'Dashboard_Dashboard', + 'General_MultiSitesSummary', + 'Referrers_Referrers', + 'Goals_Goals', + 'Goals_Ecommerce', + 'Live!', + 'ExampleUI_UiFramework' + ), array_keys($list->getCategories())); + } + + public function testGetAllCategoriesWithSubcategories_shouldFindSubcategories() + { + $list = CategoryList::get(); + + $this->assertTrue(5 < count($list->getCategory('General_Actions')->getSubcategories())); + $this->assertTrue(5 < count($list->getCategory('General_Visitors')->getSubcategories())); + $this->assertTrue($list->getCategory('General_Actions')->hasSubcategory('General_Pages')); + } + + public function test_getAllCategoriesWithSubcategories_shouldMergeCategoriesAndSubcategories() + { + $this->categories->setCategories(array( + $this->createCategory('General_Visits'), + $this->createCategory('General_Actions'), + $this->createCategory('Goals_Goals'), + $this->createCategory('Goals_Ecommerce'), + $this->createCategory('Referrers_Referrers'), + )); + $this->categories->setSubcategories(array( + $subcat1 = $this->createSubcategory('General_Actions', 'General_Pages'), + $subcat2 = $this->createSubcategory('Goals_Goals', 'General_Overview'), + $subcat3 = $this->createSubcategory('General_Actions', 'Actions_Downloads'), + $subcat4 = $this->createSubcategory('General_AnyThingNotExist', 'General_MySubcategoryId'), + $subcat5 = $this->createSubcategory('General_Visits', 'Visits'), + $subcat6 = $this->createSubcategory('Goals_Goals', '4'), + $subcat7 = $this->createSubcategory('General_Visits', 'General_Engagement'), + $subcat8 = $this->createSubcategory('Goals_Ecommerce', 'General_Overview'), + )); + + /** @var CategoryList $list */ + $list = CategoryList::get(); + + $categoryNames = array( + 'General_Visits', + 'General_Actions', + 'Goals_Goals', + 'Goals_Ecommerce', + 'Referrers_Referrers', + 'General_AnyThingNotExist' // should be created dynamically as none exists + ); + $this->assertSame($categoryNames, array_keys($list->getCategories())); + + $this->assertSubcategoriesInCategoryEquals(array($subcat5, $subcat7), 'General_Visits', $list); + $this->assertSubcategoriesInCategoryEquals(array($subcat1, $subcat3), 'General_Actions', $list); + $this->assertSubcategoriesInCategoryEquals(array($subcat2, $subcat6), 'Goals_Goals', $list); + $this->assertSubcategoriesInCategoryEquals(array($subcat8), 'Goals_Ecommerce', $list); + $this->assertSubcategoriesInCategoryEquals(array(), 'Referrers_Referrers', $list); + $this->assertSubcategoriesInCategoryEquals(array($subcat4), 'General_AnyThingNotExist', $list); + + // make sure id was actually set + $this->assertSame('General_AnyThingNotExist', $list->getCategory('General_AnyThingNotExist')->getId()); + } + + private function assertSubcategoriesInCategoryEquals($expectedSubcategories, $categoryId, CategoryList $list) + { + $this->assertSame($expectedSubcategories, $list->getCategory($categoryId)->getSubcategories()); + } + + private function createCategory($categoryId) + { + $config = new Category(); + $config->setId($categoryId); + + return $config; + } + + private function createSubcategory($categoryId, $subcategoryId) + { + $config = new Subcategory(); + $config->setId($subcategoryId); + $config->setCategoryId($categoryId); + + return $config; + } + + public function provideContainerConfig() + { + $this->categories = new Categories(StaticContainer::get('Piwik\Plugin\Manager')); + + return array( + 'Piwik\Plugin\Categories' => $this->categories + ); + } +} diff --git a/tests/PHPUnit/Integration/DataTable/Filter/PivotByDimensionTest.php b/tests/PHPUnit/Integration/DataTable/Filter/PivotByDimensionTest.php index 64ee7dac1c..dea1e7d7e9 100644 --- a/tests/PHPUnit/Integration/DataTable/Filter/PivotByDimensionTest.php +++ b/tests/PHPUnit/Integration/DataTable/Filter/PivotByDimensionTest.php @@ -91,7 +91,7 @@ class PivotByDimensionTest extends IntegrationTestCase /** * @expectedException Exception - * @expectedExceptionMessage Unsupported pivot: No segment for dimension of report 'Resolution.Resolution_WidgetGlobalVisitors' + * @expectedExceptionMessage Unsupported pivot: No segment for dimension of report 'Resolution.Resolution_Configurations' */ public function test_construction_ShouldFail_WhenDimensionIsNotSubtableAndSegmentFetchingIsEnabledButThereIsNoSegment() { diff --git a/tests/PHPUnit/Integration/Menu/MenuReportingTest.php b/tests/PHPUnit/Integration/Menu/MenuReportingTest.php deleted file mode 100644 index a9d06afa13..0000000000 --- a/tests/PHPUnit/Integration/Menu/MenuReportingTest.php +++ /dev/null @@ -1,80 +0,0 @@ -unloadPlugins(); - $this->menu = MenuReporting::getInstance(); - } - - public function tearDown() - { - MenuReporting::getInstance()->unsetInstance(); - parent::tearDown(); - } - - public function test_getMenu_shouldBeNull_IfNoItems() - { - $this->assertNull($this->menu->getMenu()); - } - - public function test_getMenu_shouldTriggerAddItemsEvent_toBeBackwardsCompatible() - { - $this->loadSomePlugins(); - - $triggered = false; - Piwik::addAction('Menu.Reporting.addItems', function () use (&$triggered) { - $triggered = true; - }); - - $this->menu->getMenu(); - - $this->assertTrue($triggered); - } - - public function test_getMenu_shouldAddMenuItemsOfReports() - { - $this->loadSomePlugins(); - - $items = $this->menu->getMenu(); - - $this->assertNotEmpty($items); - $this->assertGreaterThan(20, $items); - $this->assertEquals(array('General_Actions', 'General_Visitors'), array_keys($items)); - $this->assertNotEmpty($items['General_Actions']['General_Pages']); - $this->assertEquals('menuGetPageUrls', $items['General_Actions']['General_Pages']['_url']['action']); - } - - private function loadSomePlugins() - { - PluginManager::getInstance()->loadPlugins(array( - 'Actions', 'DevicesDetection', 'CoreVisualizations', 'API', 'Morpheus' - )); - } -} diff --git a/tests/PHPUnit/Integration/Plugin/CategoriesTest.php b/tests/PHPUnit/Integration/Plugin/CategoriesTest.php new file mode 100644 index 0000000000..925abc81b8 --- /dev/null +++ b/tests/PHPUnit/Integration/Plugin/CategoriesTest.php @@ -0,0 +1,89 @@ +categories = new Categories(StaticContainer::get('Piwik\Plugin\Manager')); + } + + public function tearDown() + { + parent::tearDown(); + unset($_GET['idSite']); + } + + public function test_getAllCategories_shouldOnlyFindCategories() + { + $categories = $this->categories->getAllCategories(); + + $this->assertGreaterThanOrEqual(4, count($categories)); + + foreach ($categories as $category) { + $this->assertTrue($category instanceof Category); + } + } + + public function test_getAllCategories_shouldHaveACategoryIdDefined() + { + $categories = $this->categories->getAllCategories(); + + foreach ($categories as $category) { + $this->assertNotEmpty($category->getId()); + } + } + + public function test_getAllSubcategories_shouldOnlyFindSubcategories() + { + $subcategories = $this->categories->getAllSubcategories(); + + $this->assertGreaterThanOrEqual(10, count($subcategories)); + + foreach ($subcategories as $subcategory) { + $this->assertTrue($subcategory instanceof Subcategory); + $this->assertNotEmpty($subcategory->getId()); + } + } + + public function test_getAllSubcategories_shouldHaveACategoryIdAndSubcategoryIdDefined() + { + $subcategories = $this->categories->getAllSubcategories(); + + foreach ($subcategories as $subcategory) { + $this->assertNotEmpty($subcategory->getId()); + $this->assertNotEmpty($subcategory->getCategoryId()); + } + } +} diff --git a/tests/PHPUnit/Integration/Plugin/WidgetsTest.php b/tests/PHPUnit/Integration/Plugin/WidgetsTest.php new file mode 100644 index 0000000000..185faba064 --- /dev/null +++ b/tests/PHPUnit/Integration/Plugin/WidgetsTest.php @@ -0,0 +1,81 @@ +widgets = new Widgets(StaticContainer::get('Piwik\Plugin\Manager')); + } + + public function tearDown() + { + parent::tearDown(); + unset($_GET['idSite']); + } + + public function test_getWidgetContainerConfigs_shouldOnlyFindWidgetContainerConfigs() + { + $configs = $this->widgets->getWidgetContainerConfigs(); + + $this->assertGreaterThanOrEqual(3, count($configs)); + + foreach ($configs as $config) { + $this->assertTrue($config instanceof WidgetContainerConfig); + } + } + + public function test_getWidgetConfigs_shouldFindWidgetConfigs() + { + $configs = $this->widgets->getWidgetConfigs(); + + $this->assertGreaterThanOrEqual(10, count($configs)); + + foreach ($configs as $config) { + $this->assertTrue($config instanceof WidgetConfig); + $this->assertFalse($config instanceof WidgetContainerConfig); + } + } + + public function test_getWidgetConfigs_shouldSetModuleAndActionForEachConfig() + { + $configs = $this->widgets->getWidgetConfigs(); + + foreach ($configs as $config) { + $this->assertNotEmpty($config->getModule()); + $this->assertNotEmpty($config->getAction()); + } + } +} diff --git a/tests/PHPUnit/Integration/Report/ReportsTest.php b/tests/PHPUnit/Integration/Report/ReportsTest.php new file mode 100644 index 0000000000..9681d73e64 --- /dev/null +++ b/tests/PHPUnit/Integration/Report/ReportsTest.php @@ -0,0 +1,72 @@ +unloadAllPlugins(); + + $reports = new Reports(); + $report = $reports->getAllReports(); + + $this->assertEquals(array(), $report); + } + + public function test_getAllReports_ShouldFindAllAvailableReports() + { + $this->loadExampleReportPlugin(); + $this->loadMorePlugins(); + + $reports = new Reports(); + $reports = $reports->getAllReports(); + + $this->assertGreaterThan(20, count($reports)); + + foreach ($reports as $report) { + $this->assertInstanceOf('Piwik\Plugin\Report', $report); + } + } + + private function loadExampleReportPlugin() + { + PluginManager::getInstance()->loadPlugins(array('ExampleReport')); + } + + private function loadMorePlugins() + { + PluginManager::getInstance()->loadPlugins(array('Actions', 'DevicesDetection', 'CoreVisualizations', 'API', 'Morpheus')); + } + + private function unloadAllPlugins() + { + PluginManager::getInstance()->unloadPlugins(); + } +} diff --git a/tests/PHPUnit/Integration/ReportTest.php b/tests/PHPUnit/Integration/ReportTest.php index 8e535be0f2..3475cee9cf 100644 --- a/tests/PHPUnit/Integration/ReportTest.php +++ b/tests/PHPUnit/Integration/ReportTest.php @@ -16,12 +16,13 @@ use Piwik\Piwik; use Piwik\Metrics; use Piwik\Plugins\ExampleTracker\Columns\ExampleDimension; use Piwik\Plugins\Referrers\Columns\Keyword; -use Piwik\WidgetsList; +use Piwik\Plugin\Reports; +use Piwik\Report\ReportWidgetFactory; use Piwik\Translate; -use Piwik\Menu\MenuReporting; use Piwik\Plugin\Manager as PluginManager; use Piwik\Tests\Framework\Fixture; use Piwik\Tests\Framework\TestCase\IntegrationTestCase; +use Piwik\Widget\WidgetsList; class GetBasicReport extends Report { @@ -33,7 +34,7 @@ class GetBasicReport extends Report $this->order = 20; $this->module = 'TestPlugin'; $this->action = 'getBasicReport'; - $this->category = 'Goals_Goals'; + $this->categoryId = 'Goals_Goals'; $this->actionToLoadSubTables = 'invalidReport'; } } @@ -45,8 +46,7 @@ class GetAdvancedReport extends GetBasicReport parent::init(); $this->action = 'getAdvancedReport'; - $this->widgetTitle = 'Actions_WidgetPageTitlesFollowingSearch'; - $this->menuTitle = 'Actions_SubmenuPageTitles'; + $this->subcategoryId = 'Actions_SubmenuPageTitles'; $this->documentation = Piwik::translate('ExampleReportDocumentation'); $this->dimension = new ExitPageUrl(); $this->metrics = array('nb_actions', 'nb_visits'); @@ -57,6 +57,12 @@ class GetAdvancedReport extends GetBasicReport $this->constantRowsCount = true; } + public function configureWidgets(WidgetsList $widgetsList, ReportWidgetFactory $factory) + { + $widget = $factory->createWidget()->setName('Actions_WidgetPageTitlesFollowingSearch'); + $widgetsList->addWidgetConfig($widget); + } + public function set($param, $value) { $this->$param = $value; @@ -114,8 +120,6 @@ class ReportTest extends IntegrationTestCase public function tearDown() { - WidgetsList::getInstance()->_reset(); - MenuReporting::getInstance()->unsetInstance(); unset($_GET['idSite']); parent::tearDown(); } @@ -149,106 +153,13 @@ class ReportTest extends IntegrationTestCase $this->disabledReport->checkIsEnabled(); } - public function test_getWidgetTitle_shouldReturnNullIfNoTitleIsSet() - { - $this->assertNull($this->basicReport->getWidgetTitle()); - } - - public function test_getWidgetTitle_shouldReturnTranslatedTitleIfSet() - { - Translate::loadAllTranslations(); - $this->assertEquals('Page Titles Following a Site Search', $this->advancedReport->getWidgetTitle()); - Translate::reset(); - } - public function test_getCategory_shouldReturnTranslatedCategory() { Translate::loadAllTranslations(); - $this->assertEquals('Goals', $this->advancedReport->getCategory()); + $this->assertEquals('Goals_Goals', $this->advancedReport->getCategoryId()); Translate::reset(); } - public function test_configureWidget_shouldNotAddAWidgetIfNoWidgetTitleIsSet() - { - $widgets = WidgetsList::get(); - $this->assertCount(0, $widgets); - - $this->basicReport->configureWidget(WidgetsList::getInstance()); - - $widgets = WidgetsList::get(); - $this->assertCount(0, $widgets); - } - - public function test_configureWidget_shouldAddAWidgetIfAWidgetTitleIsSet() - { - $widgets = WidgetsList::get(); - $this->assertCount(0, $widgets); - - $this->advancedReport->configureWidget(WidgetsList::getInstance()); - - $widgets = WidgetsList::get(); - $this->assertCount(1, $widgets); - $this->assertEquals(array(array( - 'name' => 'Actions_WidgetPageTitlesFollowingSearch', - 'uniqueId' => 'widgetTestPlugingetAdvancedReport', - 'parameters' => array('module' => 'TestPlugin', 'action' => 'getAdvancedReport') - )), $widgets['Goals_Goals']); - } - - public function test_configureWidget_shouldMixinWidgetParametersIfSet() - { - $widgets = WidgetsList::get(); - $this->assertCount(0, $widgets); - - $this->advancedReport->set('widgetParams', array('foo' => 'bar')); - $this->advancedReport->configureWidget(WidgetsList::getInstance()); - - $widgets = WidgetsList::get(); - $this->assertCount(1, $widgets); - $this->assertEquals(array('module' => 'TestPlugin', 'action' => 'getAdvancedReport', 'foo' => 'bar'), - $widgets['Goals_Goals'][0]['parameters']); - } - - public function test_configureReportingMenu_shouldNotAddAMenuIfNoWidgetTitleIsSet() - { - $menu = MenuReporting::getInstance(); - $menuItems = $menu->getMenu(); - $this->assertNull($menuItems); - - $this->basicReport->configureReportingMenu($menu); - - $menuItems = $menu->getMenu(); - $this->assertNull($menuItems); - } - - public function test_configureReportingMenu_shouldAddAMenuIfATitleIsSet() - { - $menu = MenuReporting::getInstance(); - $menuItems = $menu->getMenu(); - $this->assertNull($menuItems); - - $this->advancedReport->configureReportingMenu($menu); - - $menuItems = $menu->getMenu(); - - $expected = array( - '_tooltip' => false, - '_order' => 20, - '_hasSubmenu' => true, - 'Actions_SubmenuPageTitles' => array( - '_url' => array( - 'module' => 'TestPlugin', - 'action' => 'menuGetAdvancedReport' - ), - '_order' => 20, - '_name' => 'Actions_SubmenuPageTitles', - '_tooltip' => false, - )); - - $this->assertCount(1, $menuItems); - $this->assertEquals($expected, $menuItems['Goals_Goals']); - } - public function test_getMetrics_shouldUseDefaultMetrics() { $this->assertEquals(Metrics::getDefaultMetrics(), $this->basicReport->getMetrics()); @@ -353,7 +264,8 @@ class ReportTest extends IntegrationTestCase 'conversion_rate' => 'General_ColumnConversionRate', ), 'actionToLoadSubTables' => 'invalidReport', - 'order' => 20 + 'order' => 20, + 'subcategory' => null ) ), $reports); } @@ -390,7 +302,8 @@ class ReportTest extends IntegrationTestCase ), 'actionToLoadSubTables' => 'GetBasicReport', 'constantRowsCount' => true, - 'order' => '20' + 'order' => '20', + 'subcategory' => 'Actions_SubmenuPageTitles' ) ), $reports); } @@ -402,43 +315,20 @@ class ReportTest extends IntegrationTestCase $module = 'ExampleReport'; $action = 'getExampleReport'; - $report = Report::factory($module, $action); + $report = Reports::factory($module, $action); $this->assertInstanceOf('Piwik\Plugins\ExampleReport\Reports\GetExampleReport', $report); $this->assertEquals($module, $report->getModule()); $this->assertEquals($action, $report->getAction()); // action ucfirst should work as well - $report = Report::factory($module, ucfirst($action)); + $report = Reports::factory($module, ucfirst($action)); $this->assertInstanceOf('Piwik\Plugins\ExampleReport\Reports\GetExampleReport', $report); $this->assertEquals($module, $report->getModule()); $this->assertEquals($action, $report->getAction()); } - public function test_getAllReports_shouldNotFindAReport_IfNoPluginLoaded() - { - $this->unloadAllPlugins(); - - $report = Report::getAllReports(); - - $this->assertEquals(array(), $report); - } - - public function test_getAllReports_ShouldFindAllAvailableReports() - { - $this->loadExampleReportPlugin(); - $this->loadMorePlugins(); - - $reports = Report::getAllReports(); - - $this->assertGreaterThan(20, count($reports)); - - foreach ($reports as $report) { - $this->assertInstanceOf('Piwik\Plugin\Report', $report); - } - } - public function test_getSubtableDimension_ShouldReturnNullIfNoSubtableActionExists() { $report = new GetExampleReport(); @@ -455,7 +345,7 @@ class ReportTest extends IntegrationTestCase { PluginManager::getInstance()->loadPlugins(array('Referrers')); - $report = Report::factory('Referrers', 'getSearchEngines'); + $report = Reports::factory('Referrers', 'getSearchEngines'); $subtableDimension = $report->getSubtableDimension(); $this->assertNotNull($subtableDimension); diff --git a/tests/PHPUnit/Integration/WidgetsListTest.php b/tests/PHPUnit/Integration/WidgetsListTest.php index f741f813f3..4ca355ffe5 100644 --- a/tests/PHPUnit/Integration/WidgetsListTest.php +++ b/tests/PHPUnit/Integration/WidgetsListTest.php @@ -8,163 +8,166 @@ namespace Piwik\Tests\Integration; +use Piwik\Access; +use Piwik\Widget\WidgetConfig; use Piwik\Plugins\Goals\API; use Piwik\Tests\Framework\Mock\FakeAccess; use Piwik\Translate; -use Piwik\WidgetsList; +use Piwik\Widget\WidgetsList; use Piwik\Tests\Framework\Fixture; use Piwik\Tests\Framework\TestCase\IntegrationTestCase; /** - * @group WidgetsListTest * @group Core */ class WidgetsListTest extends IntegrationTestCase { - public function testGet() + public function setIp() { - // setup the access layer + parent::setUp(); + FakeAccess::$superUser = true; + } + public function testGet() + { Fixture::createWebsite('2009-01-04 00:11:42'); $_GET['idSite'] = 1; - WidgetsList::_reset(); $widgets = WidgetsList::get(); - WidgetsList::_reset(); + + $widgetsPerCategory = $this->getWidgetsPerCategory($widgets); // check if each category has the right number of widgets $numberOfWidgets = array( - 'VisitsSummary_VisitsSummary' => 6, - 'Live!' => 4, - 'General_Visitors' => 11, - 'General_VisitorSettings' => 5, - 'General_Actions' => 10, - 'Events_Events' => 3, - 'Actions_SubmenuSitesearch' => 5, - 'Referrers_Referrers' => 7, - 'Goals_Goals' => 1, - 'SEO' => 2, - 'Example Widgets' => 4, - 'DevicesDetection_DevicesDetection' => 8, - 'Insights_WidgetCategory' => 2 + 'Dashboard_Dashboard' => 1, + 'General_Actions' => 15, + 'General_Visitors' => 34, + 'Example Widgets' => 5, + 'SEO' => 2, + 'Goals_Goals' => 3, + 'Live!' => 2, + 'Insights_WidgetCategory' => 2, + 'ExampleUI_UiFramework' => 8, + 'Referrers_Referrers' => 9, ); // number of main categories - $this->assertEquals(count($numberOfWidgets), count($widgets)); + $this->assertEquals(count($numberOfWidgets), count($widgetsPerCategory)); foreach ($numberOfWidgets as $category => $widgetCount) { - $this->assertEquals($widgetCount, count($widgets[$category]), sprintf("Widget: %s", $category)); + $this->assertEquals($widgetCount, count($widgetsPerCategory[$category]), sprintf("Widget: %s", $category)); } } - public function testGetWithGoals() + private function getWidgetsPerCategory(WidgetsList $list) { - // setup the access layer - FakeAccess::$superUser = true; + $widgetsPerCategory = array(); + foreach ($list->getWidgetConfigs() as $widgetConfig) { + $category = $widgetConfig->getCategoryId(); + if (!isset($widgetsPerCategory[$category])) { + $widgetsPerCategory[$category] = array(); + } + + $widgetsPerCategory[$category][] = $widgetConfig; + } + return $widgetsPerCategory; + } + + public function testGetWithGoals() + { Fixture::createWebsite('2009-01-04 00:11:42'); - API::getInstance()->addGoal(1, 'Goal 1 - Thank you', 'title', 'Thank you', 'contains', $caseSensitive = false, $revenue = 10, $allowMultipleConversions = 1); + + $initialGoalsWidgets = 3; $_GET['idSite'] = 1; - WidgetsList::_reset(); - $widgets = WidgetsList::get(); - WidgetsList::_reset(); + $perCategory = $this->getWidgetsPerCategory(WidgetsList::get()); + $this->assertEquals($initialGoalsWidgets, count($perCategory['Goals_Goals'])); - // number of main categories - $this->assertEquals(13, count($widgets)); - // check that the goal widget was added - $numberOfWidgets = array( - 'Goals_Goals' => 2, - ); + API::getInstance()->addGoal(1, 'Goal 1 - Thank you', 'title', 'Thank you', 'contains', $caseSensitive = false, $revenue = 10, $allowMultipleConversions = 1); - foreach ($numberOfWidgets as $category => $widgetCount) { - $this->assertEquals($widgetCount, count($widgets[$category])); - } + $perCategory = $this->getWidgetsPerCategory(WidgetsList::get()); + + // number of main categories + $this->assertEquals(10, count($perCategory)); + $this->assertEquals($initialGoalsWidgets + 2, count($perCategory['Goals_Goals'])); // make sure widgets for that goal were added } public function testGetWithGoalsAndEcommerce() { - // setup the access layer - FakeAccess::$superUser = true; - Fixture::createWebsite('2009-01-04 00:11:42', true); API::getInstance()->addGoal(1, 'Goal 1 - Thank you', 'title', 'Thank you', 'contains', $caseSensitive = false, $revenue = 10, $allowMultipleConversions = 1); $_GET['idSite'] = 1; - WidgetsList::_reset(); - $widgets = WidgetsList::get(); - WidgetsList::_reset(); + $perCategory = $this->getWidgetsPerCategory(WidgetsList::get()); // number of main categories - $this->assertEquals(14, count($widgets)); + $this->assertEquals(11, count($perCategory)); // check if each category has the right number of widgets $numberOfWidgets = array( - 'Goals_Goals' => 2, - 'Goals_Ecommerce' => 5, + 'Goals_Goals' => 5, + 'Goals_Ecommerce' => 4, ); foreach ($numberOfWidgets as $category => $widgetCount) { - $this->assertEquals($widgetCount, count($widgets[$category])); + $this->assertEquals($widgetCount, count($perCategory[$category])); } } public function testRemove() { - // setup the access layer - FakeAccess::$superUser = true; - Fixture::createWebsite('2009-01-04 00:11:42', true); API::getInstance()->addGoal(1, 'Goal 1 - Thank you', 'title', 'Thank you', 'contains', $caseSensitive = false, $revenue = 10, $allowMultipleConversions = 1); $_GET['idSite'] = 1; - WidgetsList::_reset(); - $widgets = WidgetsList::get(); + $list = WidgetsList::get(); - $this->assertCount(14, $widgets); - WidgetsList::remove('SEO', 'NoTeXiStInG'); + $this->assertCount(11, $this->getWidgetsPerCategory($list)); - $widgets = WidgetsList::get(); - $this->assertCount(14, $widgets); + $list->remove('SEO', 'NoTeXiStInG'); - $this->assertArrayHasKey('SEO', $widgets); - $this->assertCount(2, $widgets['SEO']); + $perCategory = $this->getWidgetsPerCategory($list); + $this->assertCount(11, $perCategory); - WidgetsList::remove('SEO', 'SEO_SeoRankings'); - $widgets = WidgetsList::get(); + $this->assertArrayHasKey('SEO', $perCategory); + $this->assertCount(2, $perCategory['SEO']); - $this->assertCount(1, $widgets['SEO']); + $list->remove('SEO', 'SEO_SeoRankings'); - WidgetsList::remove('SEO'); - $widgets = WidgetsList::get(); + $perCategory = $this->getWidgetsPerCategory($list); + $this->assertCount(1, $perCategory['SEO']); - $this->assertArrayNotHasKey('SEO', $widgets); + $list->remove('SEO'); - WidgetsList::_reset(); + $perCategory = $this->getWidgetsPerCategory($list); + $this->assertArrayNotHasKey('SEO', $perCategory); } public function testIsDefined() { - // setup the access layer - FakeAccess::$superUser = true; - Translate::loadAllTranslations(); Fixture::createWebsite('2009-01-04 00:11:42', true); $_GET['idSite'] = 1; - WidgetsList::_reset(); - WidgetsList::add('Actions', 'Pages', 'Actions', 'getPageUrls'); + $config = new WidgetConfig(); + $config->setCategoryId('Actions'); + $config->setName('Pages'); + $config->setModule('Actions'); + $config->setAction('getPageUrls'); + $list = WidgetsList::get(); + $list->addWidgetConfig($config); - $this->assertTrue(WidgetsList::isDefined('Actions', 'getPageUrls')); - $this->assertFalse(WidgetsList::isDefined('Actions', 'inValiD')); + $this->assertTrue($list->isDefined('Actions', 'getPageUrls')); + $this->assertFalse($list->isDefined('Actions', 'inValiD')); Translate::reset(); } diff --git a/tests/PHPUnit/System/ApiGetReportMetadataTest.php b/tests/PHPUnit/System/ApiGetReportMetadataTest.php index 1270361c39..6b20309230 100755 --- a/tests/PHPUnit/System/ApiGetReportMetadataTest.php +++ b/tests/PHPUnit/System/ApiGetReportMetadataTest.php @@ -8,6 +8,7 @@ namespace Piwik\Tests\System; use Piwik\API\Proxy; +use Piwik\Cache; use Piwik\Tests\Framework\TestCase\SystemTestCase; use Piwik\Tests\Fixtures\ThreeGoalsOnePageview; diff --git a/tests/PHPUnit/System/AutoSuggestAPITest.php b/tests/PHPUnit/System/AutoSuggestAPITest.php index 2cb5e0282d..62a0175d01 100644 --- a/tests/PHPUnit/System/AutoSuggestAPITest.php +++ b/tests/PHPUnit/System/AutoSuggestAPITest.php @@ -19,6 +19,7 @@ use Piwik\Tests\Framework\TestCase\SystemTestCase; use Piwik\Tests\Fixtures\ManyVisitsWithGeoIP; use Piwik\Tests\Framework\Fixture; use Piwik\Tracker\Cache; +use Piwik\Cache as PiwikCache; /** * testing a the auto suggest API for all known segments @@ -155,6 +156,7 @@ class AutoSuggestAPITest extends SystemTestCase { // Refresh cache for CustomVariables\Model Cache::clearCacheGeneral(); + PiwikCache::getTransientCache()->flushAll(); $segments = array(); diff --git a/tests/PHPUnit/System/expected/test_CustomEvents_Events.getAction_flat__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_CustomEvents_Events.getAction_flat__API.getProcessedReport_day.xml index 108dc6b91f..38b110885e 100644 --- a/tests/PHPUnit/System/expected/test_CustomEvents_Events.getAction_flat__API.getProcessedReport_day.xml +++ b/tests/PHPUnit/System/expected/test_CustomEvents_Events.getAction_flat__API.getProcessedReport_day.xml @@ -3,7 +3,8 @@ Piwik test 3 Jan 10 - 9 Jan 10 - Events + Actions + Events Event Actions Events getAction diff --git a/tests/PHPUnit/System/expected/test_CustomEvents_Events.getAction_lastN__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_CustomEvents_Events.getAction_lastN__API.getProcessedReport_day.xml index dfc90321e5..fc22061c34 100644 --- a/tests/PHPUnit/System/expected/test_CustomEvents_Events.getAction_lastN__API.getProcessedReport_day.xml +++ b/tests/PHPUnit/System/expected/test_CustomEvents_Events.getAction_lastN__API.getProcessedReport_day.xml @@ -3,7 +3,8 @@ Piwik test 3 Jan 10 - 9 Jan 10 - Events + Actions + Events Event Actions Events getAction diff --git a/tests/PHPUnit/System/expected/test_CustomEvents_Events.getCategory_flat__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_CustomEvents_Events.getCategory_flat__API.getProcessedReport_day.xml index 5536cff251..cc9871433d 100644 --- a/tests/PHPUnit/System/expected/test_CustomEvents_Events.getCategory_flat__API.getProcessedReport_day.xml +++ b/tests/PHPUnit/System/expected/test_CustomEvents_Events.getCategory_flat__API.getProcessedReport_day.xml @@ -3,7 +3,8 @@ Piwik test 3 Jan 10 - 9 Jan 10 - Events + Actions + Events Event Categories Events getCategory diff --git a/tests/PHPUnit/System/expected/test_CustomEvents_Events.getCategory_lastN__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_CustomEvents_Events.getCategory_lastN__API.getProcessedReport_day.xml index 3f683f0611..51b565f354 100644 --- a/tests/PHPUnit/System/expected/test_CustomEvents_Events.getCategory_lastN__API.getProcessedReport_day.xml +++ b/tests/PHPUnit/System/expected/test_CustomEvents_Events.getCategory_lastN__API.getProcessedReport_day.xml @@ -3,7 +3,8 @@ Piwik test 3 Jan 10 - 9 Jan 10 - Events + Actions + Events Event Categories Events getCategory diff --git a/tests/PHPUnit/System/expected/test_CustomEvents_Events.getName_flat__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_CustomEvents_Events.getName_flat__API.getProcessedReport_day.xml index 20d04cc26b..d5f1a6a6ff 100644 --- a/tests/PHPUnit/System/expected/test_CustomEvents_Events.getName_flat__API.getProcessedReport_day.xml +++ b/tests/PHPUnit/System/expected/test_CustomEvents_Events.getName_flat__API.getProcessedReport_day.xml @@ -3,7 +3,8 @@ Piwik test 3 Jan 10 - 9 Jan 10 - Events + Actions + Events Event Names Events getName diff --git a/tests/PHPUnit/System/expected/test_CustomEvents_Events.getName_lastN__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_CustomEvents_Events.getName_lastN__API.getProcessedReport_day.xml index 7a029ed288..44a57040f1 100644 --- a/tests/PHPUnit/System/expected/test_CustomEvents_Events.getName_lastN__API.getProcessedReport_day.xml +++ b/tests/PHPUnit/System/expected/test_CustomEvents_Events.getName_lastN__API.getProcessedReport_day.xml @@ -3,7 +3,8 @@ Piwik test 3 Jan 10 - 9 Jan 10 - Events + Actions + Events Event Names Events getName diff --git a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_sortByProcessedMetric__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_sortByProcessedMetric__API.getProcessedReport_day.xml index 5de040b945..8d58df8c09 100644 --- a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_sortByProcessedMetric__API.getProcessedReport_day.xml +++ b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_sortByProcessedMetric__API.getProcessedReport_day.xml @@ -4,6 +4,7 @@ Sunday 3 January 2010 Actions + Pages Page URLs Actions getPageUrls diff --git a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_sortByProcessedMetric_constantRowsCountShouldKeepEmptyRows__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_sortByProcessedMetric_constantRowsCountShouldKeepEmptyRows__API.getProcessedReport_day.xml index 99d027df37..5eb322e4f5 100644 --- a/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_sortByProcessedMetric_constantRowsCountShouldKeepEmptyRows__API.getProcessedReport_day.xml +++ b/tests/PHPUnit/System/expected/test_ManyVisitorsOneWebsiteTest_sortByProcessedMetric_constantRowsCountShouldKeepEmptyRows__API.getProcessedReport_day.xml @@ -3,8 +3,9 @@ Site 1 Sunday 3 January 2010 - Visits Summary - Visits by Server Time + Visitors + Times + Visits per server time VisitTime getVisitInformationPerServerTime Server time diff --git a/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits__subtable__API.getProcessedReport_week.xml b/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits__subtable__API.getProcessedReport_week.xml index fc8e3ded56..14843d6b99 100644 --- a/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits__subtable__API.getProcessedReport_week.xml +++ b/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits__subtable__API.getProcessedReport_week.xml @@ -4,6 +4,7 @@ Week 1 March - 7 March 2010 Actions + Pages Page URLs Actions getPageUrls diff --git a/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits_hideColumns___API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits_hideColumns___API.getProcessedReport_day.xml index 279acfa5ea..e87d558301 100644 --- a/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits_hideColumns___API.getProcessedReport_day.xml +++ b/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits_hideColumns___API.getProcessedReport_day.xml @@ -4,6 +4,7 @@ Saturday 6 March 2010 Actions + Page titles Page titles Actions getPageTitles @@ -16,6 +17,18 @@ Exit rate getPageTitles + + + Entry page titles + Actions + getEntryPageTitles + + + Exit page titles + Actions + getExitPageTitles + + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getPageTitles&period=day&date=2010-03-06 index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getPageTitles&period=day&date=2010-02-05,2010-03-06 Actions_getPageTitles diff --git a/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits_showColumnsWithProcessedMetrics___API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits_showColumnsWithProcessedMetrics___API.getProcessedReport_day.xml index 209766871b..1d04867af7 100644 --- a/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits_showColumnsWithProcessedMetrics___API.getProcessedReport_day.xml +++ b/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits_showColumnsWithProcessedMetrics___API.getProcessedReport_day.xml @@ -3,8 +3,9 @@ new name Saturday 6 March 2010 - Visits Summary - Visits by Server Time + Visitors + Times + Visits per server time VisitTime getVisitInformationPerServerTime Server time diff --git a/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits_showColumns___API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits_showColumns___API.getProcessedReport_day.xml index f8e3c26999..ca84fcf6db 100644 --- a/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits_showColumns___API.getProcessedReport_day.xml +++ b/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits_showColumns___API.getProcessedReport_day.xml @@ -4,6 +4,7 @@ Saturday 6 March 2010 Actions + Page titles Page titles Actions getPageTitles @@ -20,6 +21,18 @@ Bounce Rate getPageTitles + + + Entry page titles + Actions + getEntryPageTitles + + + Exit page titles + Actions + getExitPageTitles + + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getPageTitles&period=day&date=2010-03-06 index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getPageTitles&period=day&date=2010-02-05,2010-03-06 Actions_getPageTitles diff --git a/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits_showColumns_onlyOne__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits_showColumns_onlyOne__API.getProcessedReport_day.xml index 7484c9c620..99afd65e6f 100644 --- a/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits_showColumns_onlyOne__API.getProcessedReport_day.xml +++ b/tests/PHPUnit/System/expected/test_OneVisitorTwoVisits_showColumns_onlyOne__API.getProcessedReport_day.xml @@ -3,7 +3,8 @@ new name Saturday 6 March 2010 - Visits Summary + Visitors + Overview Visits Summary VisitsSummary get diff --git a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageTitlesFollowingSiteSearch_firstSite_lastN__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageTitlesFollowingSiteSearch_firstSite_lastN__API.getProcessedReport_day.xml index e1254c611b..dbee08ed4d 100644 --- a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageTitlesFollowingSiteSearch_firstSite_lastN__API.getProcessedReport_day.xml +++ b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageTitlesFollowingSiteSearch_firstSite_lastN__API.getProcessedReport_day.xml @@ -3,7 +3,8 @@ Site 1 - Site search 3 Jan 10 - 9 Jan 10 - Site Search + Actions + Site Search Page Titles Following a Site Search Actions getPageTitlesFollowingSiteSearch @@ -17,6 +18,13 @@ 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. + + + Pages Following a Site Search + Actions + getPageUrlsFollowingSiteSearch + + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getPageTitlesFollowingSiteSearch&period=range&date=2010-01-03,2010-01-09 index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getPageTitlesFollowingSiteSearch&period=day&date=2010-01-03,2010-01-09 Actions_getPageTitlesFollowingSiteSearch diff --git a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageTitlesFollowingSiteSearch_firstSite_lastN__API.getProcessedReport_month.xml b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageTitlesFollowingSiteSearch_firstSite_lastN__API.getProcessedReport_month.xml index 358b09c180..ff965bfe37 100644 --- a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageTitlesFollowingSiteSearch_firstSite_lastN__API.getProcessedReport_month.xml +++ b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageTitlesFollowingSiteSearch_firstSite_lastN__API.getProcessedReport_month.xml @@ -3,7 +3,8 @@ Site 1 - Site search 1 Jan 10 - 31 Jul 10 - Site Search + Actions + Site Search Page Titles Following a Site Search Actions getPageTitlesFollowingSiteSearch @@ -17,6 +18,13 @@ 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. + + + Pages Following a Site Search + Actions + getPageUrlsFollowingSiteSearch + + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getPageTitlesFollowingSiteSearch&period=range&date=2010-01-03,2010-07-03 index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getPageTitlesFollowingSiteSearch&period=month&date=2010-01-03,2010-07-03 Actions_getPageTitlesFollowingSiteSearch diff --git a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageTitles_firstSite_lastN__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageTitles_firstSite_lastN__API.getProcessedReport_day.xml index 6a327dba4b..df1c9c2dba 100644 --- a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageTitles_firstSite_lastN__API.getProcessedReport_day.xml +++ b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageTitles_firstSite_lastN__API.getProcessedReport_day.xml @@ -4,6 +4,7 @@ 3 Jan 10 - 9 Jan 10 Actions + Page titles Page titles Actions getPageTitles @@ -27,6 +28,18 @@ Avg. generation time getPageTitles + + + Entry page titles + Actions + getEntryPageTitles + + + Exit page titles + Actions + getExitPageTitles + + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getPageTitles&period=range&date=2010-01-03,2010-01-09 index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getPageTitles&period=day&date=2010-01-03,2010-01-09 Actions_getPageTitles diff --git a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageTitles_firstSite_lastN__API.getProcessedReport_month.xml b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageTitles_firstSite_lastN__API.getProcessedReport_month.xml index e1f70f727c..2854fd1690 100644 --- a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageTitles_firstSite_lastN__API.getProcessedReport_month.xml +++ b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageTitles_firstSite_lastN__API.getProcessedReport_month.xml @@ -4,6 +4,7 @@ 1 Jan 10 - 31 Jul 10 Actions + Page titles Page titles Actions getPageTitles @@ -27,6 +28,18 @@ Avg. generation time getPageTitles + + + Entry page titles + Actions + getEntryPageTitles + + + Exit page titles + Actions + getExitPageTitles + + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getPageTitles&period=range&date=2010-01-03,2010-07-03 index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getPageTitles&period=month&date=2010-01-03,2010-07-03 Actions_getPageTitles diff --git a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageUrlsFollowingSiteSearch_firstSite_lastN__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageUrlsFollowingSiteSearch_firstSite_lastN__API.getProcessedReport_day.xml index a139b8c186..b70c19da05 100644 --- a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageUrlsFollowingSiteSearch_firstSite_lastN__API.getProcessedReport_day.xml +++ b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageUrlsFollowingSiteSearch_firstSite_lastN__API.getProcessedReport_day.xml @@ -3,7 +3,8 @@ Site 1 - Site search 3 Jan 10 - 9 Jan 10 - Site Search + Actions + Site Search Pages Following a Site Search Actions getPageUrlsFollowingSiteSearch @@ -17,6 +18,13 @@ 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. + + + Page Titles Following a Site Search + Actions + getPageTitlesFollowingSiteSearch + + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getPageUrlsFollowingSiteSearch&period=range&date=2010-01-03,2010-01-09 index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getPageUrlsFollowingSiteSearch&period=day&date=2010-01-03,2010-01-09 Actions_getPageUrlsFollowingSiteSearch diff --git a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageUrlsFollowingSiteSearch_firstSite_lastN__API.getProcessedReport_month.xml b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageUrlsFollowingSiteSearch_firstSite_lastN__API.getProcessedReport_month.xml index ddbfc27323..814c5bd443 100644 --- a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageUrlsFollowingSiteSearch_firstSite_lastN__API.getProcessedReport_month.xml +++ b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageUrlsFollowingSiteSearch_firstSite_lastN__API.getProcessedReport_month.xml @@ -3,7 +3,8 @@ Site 1 - Site search 1 Jan 10 - 31 Jul 10 - Site Search + Actions + Site Search Pages Following a Site Search Actions getPageUrlsFollowingSiteSearch @@ -17,6 +18,13 @@ 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. + + + Page Titles Following a Site Search + Actions + getPageTitlesFollowingSiteSearch + + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getPageUrlsFollowingSiteSearch&period=range&date=2010-01-03,2010-07-03 index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getPageUrlsFollowingSiteSearch&period=month&date=2010-01-03,2010-07-03 Actions_getPageUrlsFollowingSiteSearch diff --git a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageUrls_firstSite_lastN__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageUrls_firstSite_lastN__API.getProcessedReport_day.xml index 540d585878..84e770988d 100644 --- a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageUrls_firstSite_lastN__API.getProcessedReport_day.xml +++ b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageUrls_firstSite_lastN__API.getProcessedReport_day.xml @@ -4,6 +4,7 @@ 3 Jan 10 - 9 Jan 10 Actions + Pages Page URLs Actions getPageUrls diff --git a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageUrls_firstSite_lastN__API.getProcessedReport_month.xml b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageUrls_firstSite_lastN__API.getProcessedReport_month.xml index d1babd5956..0d002112b6 100644 --- a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageUrls_firstSite_lastN__API.getProcessedReport_month.xml +++ b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getPageUrls_firstSite_lastN__API.getProcessedReport_month.xml @@ -4,6 +4,7 @@ 1 Jan 10 - 31 Jul 10 Actions + Pages Page URLs Actions getPageUrls diff --git a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchCategories_firstSite_lastN__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchCategories_firstSite_lastN__API.getProcessedReport_day.xml index 48dec5534c..eef856b9c5 100644 --- a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchCategories_firstSite_lastN__API.getProcessedReport_day.xml +++ b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchCategories_firstSite_lastN__API.getProcessedReport_day.xml @@ -3,7 +3,8 @@ Site 1 - Site search 3 Jan 10 - 9 Jan 10 - Site Search + Actions + Site Search Search Categories Actions getSiteSearchCategories diff --git a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchCategories_firstSite_lastN__API.getProcessedReport_month.xml b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchCategories_firstSite_lastN__API.getProcessedReport_month.xml index cb33390062..69fdfe1242 100644 --- a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchCategories_firstSite_lastN__API.getProcessedReport_month.xml +++ b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchCategories_firstSite_lastN__API.getProcessedReport_month.xml @@ -3,7 +3,8 @@ Site 1 - Site search 1 Jan 10 - 31 Jul 10 - Site Search + Actions + Site Search Search Categories Actions getSiteSearchCategories diff --git a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchKeywords_firstSite_lastN__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchKeywords_firstSite_lastN__API.getProcessedReport_day.xml index 12f71c1e5f..40ecf0f41b 100644 --- a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchKeywords_firstSite_lastN__API.getProcessedReport_day.xml +++ b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchKeywords_firstSite_lastN__API.getProcessedReport_day.xml @@ -3,7 +3,8 @@ Site 1 - Site search 3 Jan 10 - 9 Jan 10 - Site Search + Actions + Site Search Site Search Keywords Actions getSiteSearchKeywords diff --git a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchKeywords_firstSite_lastN__API.getProcessedReport_month.xml b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchKeywords_firstSite_lastN__API.getProcessedReport_month.xml index 547fb4f58e..10c1eeeb9a 100644 --- a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchKeywords_firstSite_lastN__API.getProcessedReport_month.xml +++ b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchKeywords_firstSite_lastN__API.getProcessedReport_month.xml @@ -3,7 +3,8 @@ Site 1 - Site search 1 Jan 10 - 31 Jul 10 - Site Search + Actions + Site Search Site Search Keywords Actions getSiteSearchKeywords diff --git a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchNoResultKeywords_firstSite_lastN__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchNoResultKeywords_firstSite_lastN__API.getProcessedReport_day.xml index 1f90a947fa..e1fe80b601 100644 --- a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchNoResultKeywords_firstSite_lastN__API.getProcessedReport_day.xml +++ b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchNoResultKeywords_firstSite_lastN__API.getProcessedReport_day.xml @@ -3,7 +3,8 @@ Site 1 - Site search 3 Jan 10 - 9 Jan 10 - Site Search + Actions + Site Search Search Keywords with No Results Actions getSiteSearchNoResultKeywords diff --git a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchNoResultKeywords_firstSite_lastN__API.getProcessedReport_month.xml b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchNoResultKeywords_firstSite_lastN__API.getProcessedReport_month.xml index 8619ee693c..8ca73782a9 100644 --- a/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchNoResultKeywords_firstSite_lastN__API.getProcessedReport_month.xml +++ b/tests/PHPUnit/System/expected/test_SiteSearch_Actions.getSiteSearchNoResultKeywords_firstSite_lastN__API.getProcessedReport_month.xml @@ -3,7 +3,8 @@ Site 1 - Site search 1 Jan 10 - 31 Jul 10 - Site Search + Actions + Site Search Search Keywords with No Results Actions getSiteSearchNoResultKeywords diff --git a/tests/PHPUnit/System/expected/test_SiteSearch_CustomVariables.getCustomVariables_firstSite_lastN__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_SiteSearch_CustomVariables.getCustomVariables_firstSite_lastN__API.getProcessedReport_day.xml index 7b71c193d5..bbc0938754 100644 --- a/tests/PHPUnit/System/expected/test_SiteSearch_CustomVariables.getCustomVariables_firstSite_lastN__API.getProcessedReport_day.xml +++ b/tests/PHPUnit/System/expected/test_SiteSearch_CustomVariables.getCustomVariables_firstSite_lastN__API.getProcessedReport_day.xml @@ -4,6 +4,7 @@ 3 Jan 10 - 9 Jan 10 Visitors + Custom Variables Custom Variables CustomVariables getCustomVariables diff --git a/tests/PHPUnit/System/expected/test_SiteSearch_CustomVariables.getCustomVariables_firstSite_lastN__API.getProcessedReport_month.xml b/tests/PHPUnit/System/expected/test_SiteSearch_CustomVariables.getCustomVariables_firstSite_lastN__API.getProcessedReport_month.xml index b43322948f..e0aa4d5446 100644 --- a/tests/PHPUnit/System/expected/test_SiteSearch_CustomVariables.getCustomVariables_firstSite_lastN__API.getProcessedReport_month.xml +++ b/tests/PHPUnit/System/expected/test_SiteSearch_CustomVariables.getCustomVariables_firstSite_lastN__API.getProcessedReport_month.xml @@ -4,6 +4,7 @@ 1 Jan 10 - 31 Jul 10 Visitors + Custom Variables Custom Variables CustomVariables getCustomVariables diff --git a/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_Actions.getOutlinks_firstSite_lastN__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_Actions.getOutlinks_firstSite_lastN__API.getProcessedReport_day.xml index 85885d4462..c937a953c7 100644 --- a/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_Actions.getOutlinks_firstSite_lastN__API.getProcessedReport_day.xml +++ b/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_Actions.getOutlinks_firstSite_lastN__API.getProcessedReport_day.xml @@ -4,6 +4,7 @@ 3 Jan 10 - 9 Jan 10 Actions + Outlinks Outlinks Actions getOutlinks diff --git a/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_Actions.getPageTitles_firstSite_lastN__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_Actions.getPageTitles_firstSite_lastN__API.getProcessedReport_day.xml index 8051442f3d..2bc3553366 100644 --- a/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_Actions.getPageTitles_firstSite_lastN__API.getProcessedReport_day.xml +++ b/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_Actions.getPageTitles_firstSite_lastN__API.getProcessedReport_day.xml @@ -4,6 +4,7 @@ 3 Jan 10 - 9 Jan 10 Actions + Page titles Page titles Actions getPageTitles @@ -28,6 +29,18 @@ Avg. generation time getPageTitles + + + Entry page titles + Actions + getEntryPageTitles + + + Exit page titles + Actions + getExitPageTitles + + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getPageTitles&period=range&date=2010-01-03,2010-01-09 index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getPageTitles&period=day&date=2010-01-03,2010-01-09 Actions_getPageTitles diff --git a/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_Actions.getPageUrls_firstSite_lastN__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_Actions.getPageUrls_firstSite_lastN__API.getProcessedReport_day.xml index e7b22c9604..a67ceb3264 100644 --- a/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_Actions.getPageUrls_firstSite_lastN__API.getProcessedReport_day.xml +++ b/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_Actions.getPageUrls_firstSite_lastN__API.getProcessedReport_day.xml @@ -4,6 +4,7 @@ 3 Jan 10 - 9 Jan 10 Actions + Pages Page URLs Actions getPageUrls diff --git a/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_Referrers.getWebsites_firstSite_lastN__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_Referrers.getWebsites_firstSite_lastN__API.getProcessedReport_day.xml index f77187ebe6..de7b01af17 100644 --- a/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_Referrers.getWebsites_firstSite_lastN__API.getProcessedReport_day.xml +++ b/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_Referrers.getWebsites_firstSite_lastN__API.getProcessedReport_day.xml @@ -4,6 +4,7 @@ 3 Jan 10 - 9 Jan 10 Referrers + Websites & Social Websites Referrers getWebsites diff --git a/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_VisitFrequency.get_firstSite_lastN__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_VisitFrequency.get_firstSite_lastN__API.getProcessedReport_day.xml index 5d889eb52f..3659833662 100644 --- a/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_VisitFrequency.get_firstSite_lastN__API.getProcessedReport_day.xml +++ b/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_VisitFrequency.get_firstSite_lastN__API.getProcessedReport_day.xml @@ -4,6 +4,7 @@ 3 Jan 10 - 9 Jan 10 Visitors + Engagement Returning Visits VisitFrequency get diff --git a/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_VisitorInterest.getNumberOfVisitsByDaysSinceLast_firstSite_lastN__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_VisitorInterest.getNumberOfVisitsByDaysSinceLast_firstSite_lastN__API.getProcessedReport_day.xml index b7072a3a35..a75f643726 100644 --- a/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_VisitorInterest.getNumberOfVisitsByDaysSinceLast_firstSite_lastN__API.getProcessedReport_day.xml +++ b/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_VisitorInterest.getNumberOfVisitsByDaysSinceLast_firstSite_lastN__API.getProcessedReport_day.xml @@ -4,6 +4,7 @@ 3 Jan 10 - 9 Jan 10 Visitors + Engagement Visits by days since last visit VisitorInterest getNumberOfVisitsByDaysSinceLast diff --git a/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_VisitsSummary.get_firstSite_lastN__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_VisitsSummary.get_firstSite_lastN__API.getProcessedReport_day.xml index 63b6741a62..b5ba74182e 100644 --- a/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_VisitsSummary.get_firstSite_lastN__API.getProcessedReport_day.xml +++ b/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_VisitsSummary.get_firstSite_lastN__API.getProcessedReport_day.xml @@ -3,7 +3,8 @@ Site 1 3 Jan 10 - 9 Jan 10 - Visits Summary + Visitors + Overview Visits Summary VisitsSummary get diff --git a/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_csv__ScheduledReports.generateReport_month.original.csv b/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_csv__ScheduledReports.generateReport_month.original.csv index 98bd55b5b0..8d071ce80a 100644 --- a/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_csv__ScheduledReports.generateReport_month.original.csv +++ b/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_csv__ScheduledReports.generateReport_month.original.csv @@ -7,34 +7,172 @@ Visits Summary nb_uniq_visitors,nb_visits,nb_actions,max_actions,nb_actions_per_visit,avg_time_on_site,bounce_rate 2,11,43,5,3.9,00:10:55,27% -Visits by Server Time +Custom Variables +No data available + +Device type +label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate +Unknown,8,40,0%,5,00:15:01,0% +Desktop,3,3,0%,1,00:00:00,100% + +Device model +label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate +Unknown,11,43,0%,3.9,00:10:55,27% + +Device brand +label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate +Unknown,11,43,0%,3.9,00:10:55,27% + +Screen Resolution +label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate +800x300,9,41,0%,4.6,00:13:21,11% +1024x768,2,2,0%,1,00:00:00,100% + +Operating System versions +label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate +Unknown,8,40,0%,5,00:15:01,0% +Windows XP,3,3,0%,1,00:00:00,100% + +Browsers +label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate +Unknown,8,40,0%,5,00:15:01,0% +Firefox,2,2,0%,1,00:00:00,100% +Opera,1,1,0%,1,00:00:00,100% + +Browser version +label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate +Unknown,8,40,0%,5,00:15:01,0% +Firefox 3.6,2,2,0%,1,00:00:00,100% +Opera 9.63,1,1,0%,1,00:00:00,100% + +Configurations +label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate +Unknown / Unknown / 800x300,8,40,0%,5,00:15:01,0% +Windows / Firefox / 1024x768,2,2,0%,1,00:00:00,100% +Windows / Opera / 800x300,1,1,0%,1,00:00:00,100% + +Operating System families +label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate +Unknown,8,40,0%,5,00:15:01,0% +Windows,3,3,0%,1,00:00:00,100% + +Browser engines +label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate +Unknown,8,40,0%,5,00:15:01,0% +Gecko (Firefox),2,2,0%,1,00:00:00,100% +Presto (Opera),1,1,0%,1,00:00:00,100% + +Browser Plugins +label,nb_visits,nb_visits_percentage +Cookie,11,100% +Flash,11,100% +Java,11,100% +Director,0,0% +Gears,0,0% +Pdf,0,0% +Quicktime,0,0% +Realplayer,0,0% +Silverlight,0,0% +Windowsmedia,0,0% + +Country label,nb_visits,nb_actions,nb_actions_per_visit,avg_time_on_site,bounce_rate,revenue -0h,1,1,1,00:00:00,100%,$ 0 -1h,0,0,0,00:00:00,0%,$ 0 -2h,0,0,0,00:00:00,0%,$ 0 -3h,0,0,0,00:00:00,0%,$ 0 -4h,0,0,0,00:00:00,0%,$ 0 -5h,0,0,0,00:00:00,0%,$ 0 -6h,0,0,0,00:00:00,0%,$ 0 -7h,0,0,0,00:00:00,0%,$ 0 -8h,0,0,0,00:00:00,0%,$ 0 -9h,0,0,0,00:00:00,0%,$ 0 -10h,0,0,0,00:00:00,0%,$ 0 -11h,8,40,5,00:15:01,0%,$ 0 -12h,1,1,1,00:00:00,100%,$ 0 -13h,0,0,0,00:00:00,0%,$ 0 -14h,0,0,0,00:00:00,0%,$ 0 -15h,0,0,0,00:00:00,0%,$ 0 -16h,0,0,0,00:00:00,0%,$ 0 -17h,0,0,0,00:00:00,0%,$ 0 -18h,0,0,0,00:00:00,0%,$ 0 -19h,0,0,0,00:00:00,0%,$ 0 -20h,0,0,0,00:00:00,0%,$ 0 -21h,0,0,0,00:00:00,0%,$ 0 -22h,0,0,0,00:00:00,0%,$ 0 -23h,1,1,1,00:00:00,100%,$ 0 +Unknown,8,40,5,00:15:01,0%,$ 0 +France,3,3,1,00:00:00,100%,$ 0 + +Continent +label,nb_visits,nb_actions,nb_actions_per_visit,avg_time_on_site,bounce_rate,revenue +Unknown,8,40,5,00:15:01,0%,$ 0 +Europe,3,3,1,00:00:00,100%,$ 0 + +Region +label,nb_visits,nb_actions,nb_actions_per_visit,avg_time_on_site,bounce_rate,revenue +Unknown,11,43,3.9,00:10:55,27%,$ 0 + +Browser language +label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate +Unknown,8,40,0%,5,00:15:01,0% +French,3,3,0%,1,00:00:00,100% + +City +label,nb_visits,nb_actions,nb_actions_per_visit,avg_time_on_site,bounce_rate,revenue +Unknown,11,43,3.9,00:10:55,27%,$ 0 + +Language code +label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate +Unknown (xx),8,40,0%,5,00:15:01,0% +French (fr),3,3,0%,1,00:00:00,100% + +Provider +label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate +Unknown,11,43,0%,3.9,00:10:55,27% + +Length of Visits +label,nb_visits +0-10s,3 +11-30s,0 +31-60s,0 +1-2 min,0 +2-4 min,0 +4-7 min,0 +7-10 min,0 +10-15 min,0 +15-30 min,8 +30+ min,0 + +Pages per Visit +label,nb_visits +1 page,3 +2 pages,0 +3 pages,0 +4 pages,0 +5 pages,8 +6-7 pages,0 +8-10 pages,0 +11-14 pages,0 +15-20 pages,0 +21+ pages,0 + +Visits by Visit Number +label,nb_visits,nb_visits_percentage +1 visit,3,27% +2 visits,8,73% +3 visits,0,0% +4 visits,0,0% +5 visits,0,0% +6 visits,0,0% +7 visits,0,0% +8 visits,0,0% +9-14 visits,0,0% +15-25 visits,0,0% +26-50 visits,0,0% +51-100 visits,0,0% +101-200 visits,0,0% +201+ visits,0,0% -Visits by Local Time +Visits by days since last visit +label,nb_visits +New visits,2 +0 days,1 +1 day,0 +2 days,1 +3 days,1 +4 days,1 +5 days,1 +6 days,1 +7 days,1 +8-14 days,2 +15-30 days,0 +31-60 days,0 +61-120 days,0 +121-364 days,0 +365+ days,0 + +Returning Visits +nb_uniq_visitors_returning,nb_users_returning,nb_visits_returning,nb_actions_returning,max_actions_returning,bounce_rate_returning,nb_actions_per_visit_returning,avg_time_on_site_returning +2,0,9,41,5,11%,4.6,00:13:21 + +Visits per local time label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate 0h,0,0,0%,0,00:00:00,0% 1h,0,0,0%,0,00:00:00,0% @@ -61,6 +199,33 @@ label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site 22h,0,0,0%,0,00:00:00,0% 23h,0,0,0%,0,00:00:00,0% +Visits per server time +label,nb_visits,nb_actions,nb_actions_per_visit,avg_time_on_site,bounce_rate,revenue +0h,1,1,1,00:00:00,100%,$ 0 +1h,0,0,0,00:00:00,0%,$ 0 +2h,0,0,0,00:00:00,0%,$ 0 +3h,0,0,0,00:00:00,0%,$ 0 +4h,0,0,0,00:00:00,0%,$ 0 +5h,0,0,0,00:00:00,0%,$ 0 +6h,0,0,0,00:00:00,0%,$ 0 +7h,0,0,0,00:00:00,0%,$ 0 +8h,0,0,0,00:00:00,0%,$ 0 +9h,0,0,0,00:00:00,0%,$ 0 +10h,0,0,0,00:00:00,0%,$ 0 +11h,8,40,5,00:15:01,0%,$ 0 +12h,1,1,1,00:00:00,100%,$ 0 +13h,0,0,0,00:00:00,0%,$ 0 +14h,0,0,0,00:00:00,0%,$ 0 +15h,0,0,0,00:00:00,0%,$ 0 +16h,0,0,0,00:00:00,0%,$ 0 +17h,0,0,0,00:00:00,0%,$ 0 +18h,0,0,0,00:00:00,0%,$ 0 +19h,0,0,0,00:00:00,0%,$ 0 +20h,0,0,0,00:00:00,0%,$ 0 +21h,0,0,0,00:00:00,0%,$ 0 +22h,0,0,0,00:00:00,0%,$ 0 +23h,1,1,1,00:00:00,100%,$ 0 + Visits by Day of Week label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate Monday,2,6,0%,3,00:07:31,50% @@ -71,44 +236,6 @@ Friday,1,5,0%,5,00:15:01,0% Saturday,1,5,0%,5,00:15:01,0% Sunday,3,7,0%,2.3,00:05:00,67% -Screen Resolution -label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate -800x300,9,41,0%,4.6,00:13:21,11% -1024x768,2,2,0%,1,00:00:00,100% - -Browser Plugins -label,nb_visits,nb_visits_percentage -Cookie,11,100% -Flash,11,100% -Java,11,100% -Director,0,0% -Gears,0,0% -Pdf,0,0% -Quicktime,0,0% -Realplayer,0,0% -Silverlight,0,0% -Windowsmedia,0,0% - -Visitor Configuration -label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate -Unknown / Unknown / 800x300,8,40,0%,5,00:15:01,0% -Windows / Firefox / 1024x768,2,2,0%,1,00:00:00,100% -Windows / Opera / 800x300,1,1,0%,1,00:00:00,100% - -Browser language -label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate -Unknown,8,40,0%,5,00:15:01,0% -French,3,3,0%,1,00:00:00,100% - -Language code -label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate -Unknown (xx),8,40,0%,5,00:15:01,0% -French (fr),3,3,0%,1,00:00:00,100% - -Actions - Main metrics -nb_pageviews,nb_uniq_pageviews,nb_downloads,nb_uniq_downloads,nb_outlinks,nb_uniq_outlinks,nb_searches,nb_keywords,avg_time_generation -43,27,0,0,0,0,0,0,0.3s - Page URLs label,nb_visits,nb_hits,bounce_rate,avg_time_on_page,exit_rate,avg_time_generation /index.htm,9,9,11%,00:05:20,11%,0.3s @@ -134,26 +261,25 @@ Checkout,8,8,0%,00:00:00,100%,0.45s first page view,2,2,100%,00:00:00,100%,0.14s Page Name not defined,1,1,0%,00:00:00,0%,0.22s -Entry page titles -label,entry_nb_visits,entry_bounce_count,bounce_rate,avg_time_generation -second visitor,8,0,0%,0.25s - first page view,2,2,100%,0.14s +Site Search Keywords +No data available -Exit page titles -label,nb_visits,exit_nb_visits,exit_rate,avg_time_generation -Checkout,8,8,100%,0.45s - first page view,2,2,100%,0.14s +Pages Following a Site Search +No data available -Outlinks +Search Keywords with No Results No data available -Downloads +Page Titles Following a Site Search No data available -Content Name +Search Categories No data available -Content Piece +Outlinks +No data available + +Downloads No data available Event Categories @@ -165,20 +291,25 @@ No data available Event Names No data available -Site Search Keywords +Content Name No data available -Search Keywords with No Results +Content Piece No data available -Search Categories -No data available +Actions - Main metrics +nb_pageviews,nb_uniq_pageviews,nb_downloads,nb_uniq_downloads,nb_outlinks,nb_uniq_outlinks,nb_searches,nb_keywords,avg_time_generation +43,27,0,0,0,0,0,0,0.3s -Pages Following a Site Search -No data available +Entry page titles +label,entry_nb_visits,entry_bounce_count,bounce_rate,avg_time_generation +second visitor,8,0,0%,0.25s + first page view,2,2,100%,0.14s -Page Titles Following a Site Search -No data available +Exit page titles +label,nb_visits,exit_nb_visits,exit_rate,avg_time_generation +Checkout,8,8,100%,0.45s + first page view,2,2,100%,0.14s Referrer Type label,nb_visits,nb_actions,nb_actions_per_visit,avg_time_on_site,bounce_rate,revenue @@ -194,20 +325,20 @@ goal-matching-url-parameter,4,20,0%,5,00:15:01,0% Keywords No data available +Search Engines +No data available + Websites label,nb_visits,nb_actions,nb_actions_per_visit,avg_time_on_site,bounce_rate,revenue referrer.com,6,22,3.7,00:10:01,33%,$ 0 -Search Engines +Social Networks No data available Campaigns label,nb_visits,nb_actions,nb_actions_per_visit,avg_time_on_site,bounce_rate,revenue goal-matching-url-parameter,4,20,5,00:15:01,0%,$ 0 -Social Networks -No data available - Goals nb_conversions,nb_visits_converted,revenue,conversion_rate 0,0,$ 0,0% @@ -218,130 +349,15 @@ No data available Days to Conversion No data available -Country -label,nb_visits,nb_actions,nb_actions_per_visit,avg_time_on_site,bounce_rate,revenue -Unknown,8,40,5,00:15:01,0%,$ 0 -France,3,3,1,00:00:00,100%,$ 0 - -Continent -label,nb_visits,nb_actions,nb_actions_per_visit,avg_time_on_site,bounce_rate,revenue -Unknown,8,40,5,00:15:01,0%,$ 0 -Europe,3,3,1,00:00:00,100%,$ 0 - -Region -label,nb_visits,nb_actions,nb_actions_per_visit,avg_time_on_site,bounce_rate,revenue -Unknown,11,43,3.9,00:10:55,27%,$ 0 - -City -label,nb_visits,nb_actions,nb_actions_per_visit,avg_time_on_site,bounce_rate,revenue -Unknown,11,43,3.9,00:10:55,27%,$ 0 - -Custom Variables +Data tables No data available -Length of Visits -label,nb_visits -0-10s,3 -11-30s,0 -31-60s,0 -1-2 min,0 -2-4 min,0 -4-7 min,0 -7-10 min,0 -10-15 min,0 -15-30 min,8 -30+ min,0 - -Pages per Visit -label,nb_visits -1 page,3 -2 pages,0 -3 pages,0 -4 pages,0 -5 pages,8 -6-7 pages,0 -8-10 pages,0 -11-14 pages,0 -15-20 pages,0 -21+ pages,0 - -Visits by Visit Number -label,nb_visits,nb_visits_percentage -1 visit,3,27% -2 visits,8,73% -3 visits,0,0% -4 visits,0,0% -5 visits,0,0% -6 visits,0,0% -7 visits,0,0% -8 visits,0,0% -9-14 visits,0,0% -15-25 visits,0,0% -26-50 visits,0,0% -51-100 visits,0,0% -101-200 visits,0,0% -201+ visits,0,0% - -Visits by days since last visit -label,nb_visits -New visits,2 -0 days,1 -1 day,0 -2 days,1 -3 days,1 -4 days,1 -5 days,1 -6 days,1 -7 days,1 -8-14 days,2 -15-30 days,0 -31-60 days,0 -61-120 days,0 -121-364 days,0 -365+ days,0 - -Returning Visits -nb_uniq_visitors_returning,nb_users_returning,nb_visits_returning,nb_actions_returning,max_actions_returning,bounce_rate_returning,nb_actions_per_visit_returning,avg_time_on_site_returning -2,0,9,41,5,11%,4.6,00:13:21 - -Device type -label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate -Unknown,8,40,0%,5,00:15:01,0% -Desktop,3,3,0%,1,00:00:00,100% - -Visitor Browser -label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate -Unknown,8,40,0%,5,00:15:01,0% -Firefox,2,2,0%,1,00:00:00,100% -Opera,1,1,0%,1,00:00:00,100% - -Device brand -label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate -Unknown,11,43,0%,3.9,00:10:55,27% - -Device model -label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate -Unknown,11,43,0%,3.9,00:10:55,27% - -Browser version -label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate -Unknown,8,40,0%,5,00:15:01,0% -Firefox 3.6,2,2,0%,1,00:00:00,100% -Opera 9.63,1,1,0%,1,00:00:00,100% - -Operating System families -label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate -Unknown,8,40,0%,5,00:15:01,0% -Windows,3,3,0%,1,00:00:00,100% +Temperatures evolution over time +No data available -Operating System versions -label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate -Unknown,8,40,0%,5,00:15:01,0% -Windows XP,3,3,0%,1,00:00:00,100% +Pie graph +No data available -Browser engines -label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate -Unknown,8,40,0%,5,00:15:01,0% -Gecko (Firefox),2,2,0%,1,00:00:00,100% -Presto (Opera),1,1,0%,1,00:00:00,100% +Advanced tag cloud: with logos and links +No data available diff --git a/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_html_tables_only__ScheduledReports.generateReport_month.original.html b/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_html_tables_only__ScheduledReports.generateReport_month.original.html index 5f6c7d172c..b0a975f7d7 100644 --- a/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_html_tables_only__ScheduledReports.generateReport_month.original.html +++ b/tests/PHPUnit/System/expected/test_TwoVisitors_twoWebsites_differentDays_scheduled_report_in_html_tables_only__ScheduledReports.generateReport_month.original.html @@ -31,18 +31,23 @@
  • - - Visits by Server Time + + Custom Variables
  • - - Visits by Local Time + + Device type
  • - - Visits by Day of Week + + Device model + +
  • +
  • + + Device brand
  • @@ -51,258 +56,278 @@
  • - - Browser Plugins + + Operating System versions + +
  • +
  • + + Browsers + +
  • +
  • + + Browser version
  • - Visitor Configuration + Configurations
  • - - Browser language + + Operating System families
  • - - Language code + + Browser engines
  • - - Actions - Main metrics + + Browser Plugins
  • - - Page URLs + + Country
  • - - Entry pages + + Continent
  • - - Exit pages + + Region
  • - - Page titles + + Browser language
  • - - Entry page titles + + City
  • - - Exit page titles + + Language code
  • - - Outlinks + + Provider
  • - - Downloads + + Length of Visits
  • - - Content Name + + Pages per Visit
  • - - Content Piece + + Visits by Visit Number
  • - - Event Categories + + Visits by days since last visit
  • - - Event Actions + + Returning Visits
  • - - Event Names + + Visits per local time
  • - - Site Search Keywords + + Visits per server time
  • - - Search Keywords with No Results + + Visits by Day of Week
  • - - Search Categories + + Page URLs
  • - - Pages Following a Site Search + + Entry pages
  • - - Page Titles Following a Site Search + + Exit pages
  • - - Referrer Type + + Page titles
  • - - All Referrers + + Site Search Keywords
  • - - Keywords + + Pages Following a Site Search
  • - - Websites + + Search Keywords with No Results
  • - - Search Engines + + Page Titles Following a Site Search
  • - - Campaigns + + Search Categories
  • - - Social Networks + + Outlinks
  • - - Goals + + Downloads
  • - - Visits to Conversion + + Event Categories
  • - - Days to Conversion + + Event Actions
  • - - Country + + Event Names
  • - - Continent + + Content Name
  • - - Region + + Content Piece
  • - - City + + Actions - Main metrics
  • - - Custom Variables + + Entry page titles
  • - - Length of Visits + + Exit page titles
  • - - Pages per Visit + + Referrer Type
  • - - Visits by Visit Number + + All Referrers
  • - - Visits by days since last visit + + Keywords
  • - - Returning Visits + + Search Engines
  • - - Device type + + Websites
  • - - Visitor Browser + + Social Networks
  • - - Device brand + + Campaigns
  • - - Device model + + Goals
  • - - Browser version + + Visits to Conversion
  • - - Operating System families + + Days to Conversion
  • - - Operating System versions + + Data tables
  • - - Browser engines + + Temperatures evolution over time + +
  • +
  • + + Pie graph + +
  • +
  • + + Advanced tag cloud: with logos and links
  • @@ -476,8 +501,13 @@ Back to top -

    - Visits by Server Time +

    + Custom Variables +

    + + There is no data for this report. +

    + Device type

    @@ -485,7 +515,7 @@ + +   + Unknown + +   + Desktop - + +
    -  Server time   +  Device type    Visits   @@ -503,267 +533,507 @@  Bounce Rate   -  Revenue   +  Conversion Rate  
    - 0h - 1 + 8 - 1 + 40 - 1 + 5 - 00:00:00 + 00:15:01 - 100% + 0% - $ 0 + 0%
    - 1h - 0 + 3 - 0 + 3 - 0 + 1 00:00:00 - 0% + 100% - $ 0 + 0%
    +
    + + Back to top + +

    + Device model +

    + + + + + + + + + + + + + + + + Unknown - - + +
    +  Device model   + +  Visits   + +  Actions   + +  Actions per Visit   + +  Avg. Time on Website   + +  Bounce Rate   + +  Conversion Rate   +
    - 2h - 0 + 11 - 0 + 43 - 0 + 3.9 - 00:00:00 + 00:10:55 - 0% + 27% - $ 0 + 0%
    +
    + + Back to top + +

    + Device brand +

    + + + + + + + + + + + + + + + + + +   + Unknown - + +
    +  Device brand   + +  Visits   + +  Actions   + +  Actions per Visit   + +  Avg. Time on Website   + +  Bounce Rate   + +  Conversion Rate   +
    - 3h - 0 + 11 - 0 + 43 - 0 + 3.9 - 00:00:00 + 00:10:55 - 0% + 27% - $ 0 + 0%
    +
    + + Back to top + +

    + Screen Resolution +

    + + + + + + + + + + + + + + + + 800x300 + 1024x768 - + +
    +  Resolution   + +  Visits   + +  Actions   + +  Actions per Visit   + +  Avg. Time on Website   + +  Bounce Rate   + +  Conversion Rate   +
    - 4h - 0 + 9 - 0 + 41 - 0 + 4.6 - 00:00:00 + 00:13:21 - 0% + 11% - $ 0 + 0%
    - 5h - 0 + 2 - 0 + 2 - 0 + 1 00:00:00 - 0% + 100% - $ 0 + 0%
    +
    + + Back to top + +

    + Operating System versions +

    + + + + + + + + + + + + + + + + +   + Unknown + +   + Windows XP - - - - + +
    +  Operating System versions   + +  Visits   + +  Actions   + +  Actions per Visit   + +  Avg. Time on Website   + +  Bounce Rate   + +  Conversion Rate   +
    - 6h - 0 + 8 - 0 + 40 - 0 + 5 - 00:00:00 + 00:15:01 0% - $ 0 + 0%
    - 7h - 0 + 3 - 0 + 3 - 0 + 1 00:00:00 - 0% + 100% - $ 0 + 0%
    - 8h - 0 -
    +
    + + Back to top + +

    + Browsers +

    + + + + + + + + + + + + + + + + + + + +   + Firefox + +   + Opera - - + +
    +  Browser   + +  Visits   + +  Actions   + +  Actions per Visit   + +  Avg. Time on Website   + +  Bounce Rate   + +  Conversion Rate   +
    + +   + Unknown - 0 + 8 - 0 + 40 - 00:00:00 + 5 + + 00:15:01 0% - $ 0 + 0%
    - 9h - 0 + 2 - 0 + 2 - 0 + 1 00:00:00 - 0% + 100% - $ 0 + 0%
    - 10h - 0 + 1 - 0 + 1 - 0 + 1 00:00:00 - 0% + 100% - $ 0 + 0%
    +
    + + Back to top + +

    + Browser version +

    + + + + + + + + + + + + + + + + + +   + Unknown @@ -780,18 +1050,20 @@ 0% - + + +   + Firefox 3.6 - + + +   + Opera 9.63 - + +
    +  Browser version   + +  Visits   + +  Actions   + +  Actions per Visit   + +  Avg. Time on Website   + +  Bounce Rate   + +  Conversion Rate   +
    - 11h 8 - $ 0 + 0%
    - 12h - 1 + 2 - 1 + 2 1 @@ -803,243 +1075,314 @@ 100% - $ 0 + 0%
    - 13h - 0 + 1 - 0 + 1 - 0 + 1 00:00:00 - 0% + 100% - $ 0 + 0%
    +
    + + Back to top + +

    + Configurations +

    + + + + + + + + + + + + + + + + Unknown / Unknown / 800x300 + Windows / Firefox / 1024x768 + Windows / Opera / 800x300 - - - - - - - - - - - - - - +
    +  Configuration   + +  Visits   + +  Actions   + +  Actions per Visit   + +  Avg. Time on Website   + +  Bounce Rate   + +  Conversion Rate   +
    - 14h - 0 + 8 - 0 + 40 - 0 + 5 - 00:00:00 + 00:15:01 0% - $ 0 + 0%
    - 15h - 0 + 2 - 0 + 2 - 0 + 1 00:00:00 - 0% + 100% - $ 0 + 0%
    - 16h - 0 + 1 - 0 + 1 - 0 + 1 00:00:00 - 0% - - $ 0 -
    - 17h - 0 - - 0 - - 0 - - 00:00:00 + 100% 0% - $ 0 -
    - 18h - 0 +
    +
    + + Back to top + +

    + Operating System families +

    + + + + + + + + + + + + + + + + + + + +   + Windows - + +
    +  Operating system family   + +  Visits   + +  Actions   + +  Actions per Visit   + +  Avg. Time on Website   + +  Bounce Rate   + +  Conversion Rate   +
    + +   + Unknown + 8 - 0 + 40 - 0 + 5 - 00:00:00 + 00:15:01 0% - $ 0 + 0%
    - 19h - 0 + 3 - 0 + 3 - 0 + 1 00:00:00 - 0% + 100% - $ 0 + 0%
    +
    + + Back to top + +

    + Browser engines +

    + + + + + + + + + + + + + + + + Unknown + Gecko (Firefox) - - - - - - - - - - - + + Presto (Opera) @@ -1056,7 +1399,7 @@ 100% @@ -1065,8 +1408,8 @@ Back to top -

    - Visits by Local Time +

    + Browser Plugins

    @@ -1074,69 +1417,89 @@
    +  Browser engine   + +  Visits   + +  Actions   + +  Actions per Visit   + +  Avg. Time on Website   + +  Bounce Rate   + +  Conversion Rate   +
    - 20h - 0 + 8 - 0 + 40 - 0 + 5 - 00:00:00 + 00:15:01 0% - $ 0 + 0%
    - 21h - 0 + 2 - 0 + 2 - 0 + 1 00:00:00 - 0% - - $ 0 -
    - 22h - 0 - - 0 - - 0 - - 00:00:00 + 100% 0% - $ 0 -
    - 23h 1 - $ 0 + 0%
    - - - - + +   + Cookie + + + + + + + + + +   + Director + + + + + + + + + +   + Quicktime + + + + + + + + - - + +   + Windowsmedia - - - + +
    -  Local time   +  Plugin    Visits   -  Actions   - -  Actions per Visit   - -  Avg. Time on Website   - -  Bounce Rate   - -  Conversion Rate   +  % Visits  
    - 0h - 0 + 11 - 0 + 100%
    + +   + Flash - 0 + 11 - 00:00:00 + 100%
    + +   + Java - 0% + 11 - 0% + 100%
    - 1h 0 - 0 + 0%
    + +   + Gears 0 - 00:00:00 + 0%
    + +   + Pdf - 0% + 0 0% @@ -1145,21 +1508,37 @@
    - 2h 0 - 0 + 0%
    + +   + Realplayer 0 - 00:00:00 + 0%
    + +   + Silverlight - 0% + 0 0% @@ -1168,156 +1547,300 @@
    - 3h - 0 - - 0 - 0 - 00:00:00 - - 0% - 0%
    +
    + + Back to top + +

    + Country +

    + + + + + + + + + + + + + + + + +   + Unknown + +   + France - + +
    +  Country   + +  Visits   + +  Actions   + +  Actions per Visit   + +  Avg. Time on Website   + +  Bounce Rate   + +  Revenue   +
    - 4h - 0 + 8 - 0 + 40 - 0 + 5 - 00:00:00 + 00:15:01 0% - 0% + $ 0
    - 5h - 0 + 3 - 0 + 3 - 0 + 1 00:00:00 - 0% + 100% - 0% + $ 0
    +
    + + Back to top + +

    + Continent +

    + + + + + + + + + + + + + + + + Unknown + Europe - + +
    +  Continent   + +  Visits   + +  Actions   + +  Actions per Visit   + +  Avg. Time on Website   + +  Bounce Rate   + +  Revenue   +
    - 6h - 0 + 8 - 0 + 40 - 0 + 5 - 00:00:00 + 00:15:01 0% - 0% + $ 0
    - 7h - 0 + 3 - 0 + 3 - 0 + 1 00:00:00 - 0% + 100% - 0% + $ 0
    +
    + + Back to top + +

    + Region +

    + + + + + + + + + + + + + + + + +   + Unknown - - + +
    +  Region   + +  Visits   + +  Actions   + +  Actions per Visit   + +  Avg. Time on Website   + +  Bounce Rate   + +  Revenue   +
    - 8h - 0 + 11 - 0 + 43 - 0 + 3.9 - 00:00:00 + 00:10:55 - 0% + 27% - 0% + $ 0
    +
    + + Back to top + +

    + Browser language +

    + + + + + + + + + + + + + + + + + Unknown - + + French - - + +
    +  Language   + +  Visits   + +  Actions   + +  Actions per Visit   + +  Avg. Time on Website   + +  Bounce Rate   + +  Conversion Rate   +
    - 9h - 0 + 8 - 0 + 40 - 0 + 5 - 00:00:00 + 00:15:01 0% @@ -1327,69 +1850,145 @@
    - 10h - 0 + 3 - 0 + 3 - 0 + 1 00:00:00 - 0% + 100% 0%
    +
    + + Back to top + +

    + City +

    + + + + + + + + + + + + + + + + + +   + Unknown - + +
    +  City   + +  Visits   + +  Actions   + +  Actions per Visit   + +  Avg. Time on Website   + +  Bounce Rate   + +  Revenue   +
    - 11h - 0 + 11 - 0 + 43 - 0 + 3.9 - 00:00:00 + 00:10:55 - 0% + 27% - 0% + $ 0
    +
    + + Back to top + +

    + Language code +

    + + + + + + + + + + + + + + + + Unknown (xx) + French (fr) - + +
    +  Language   + +  Visits   + +  Actions   + +  Actions per Visit   + +  Avg. Time on Website   + +  Bounce Rate   + +  Conversion Rate   +
    - 12h - 11 + 8 - 43 + 40 - 3.9 + 5 - 00:10:55 + 00:15:01 - 27% + 0% 0% @@ -1398,182 +1997,367 @@
    - 13h - 0 + 3 - 0 + 3 - 0 + 1 00:00:00 - 0% + 100% 0%
    +
    + + Back to top + +

    + Provider +

    + + + + + + + + + + + + + + + + + Unknown + + + +
    +  Provider   + +  Visits   + +  Actions   + +  Actions per Visit   + +  Avg. Time on Website   + +  Bounce Rate   + +  Conversion Rate   +
    - 14h - 0 + 11 - 0 + 43 - 0 + 3.9 - 00:00:00 + 00:10:55 - 0% + 27% 0%
    +
    + + Back to top + +

    + Length of Visits +

    + + + + + + + + + + + + + + 11-30s + + + + + + + + - - - + 2-4 min + + + + + + + + + + + + - + + + + + 30+ min + + +
    +  Visit duration   + +  Visits   +
    + 0-10s + 3 +
    - 15h 0
    + 31-60s 0
    + 1-2 min 0 - 00:00:00 - - 0% - - 0% -
    - 16h 0
    + 4-7 min 0
    + 7-10 min 0
    + 10-15 min - 00:00:00 - - 0% + 0
    + 15-30 min - 0% + 8
    - 17h 0
    +
    + + Back to top + +

    + Pages per Visit +

    + + + + + + + + + + + + + + + + - - - - + 3 pages + + + + + + + + + + + + + + + + + 11-14 pages + + + + + + + + + + +
    +  Pages per visit   + +  Visits   +
    + 1 page - 0 + 3
    + 2 pages 0 - 00:00:00 - - 0% - - 0% -
    - 18h - 0 - 0
    + 4 pages 0
    + 5 pages - 00:00:00 + 8
    + 6-7 pages - 0% + 0
    + 8-10 pages - 0% + 0
    - 19h 0
    + 15-20 pages 0
    + 21+ pages 0
    +
    + + Back to top + +

    + Visits by Visit Number +

    + + + + + + + + + + + + + + + + + + + 3 visits + + + + + + + + + 6 visits + + + + + + + + + 9-14 visits + + + + + + + + + 51-100 visits + + + + + + + +
    +  Visits by Visit Number   + +  Visits   + +  % Visits   +
    + 1 visit - 00:00:00 + 3 - 0% + 27%
    + 2 visits - 0% + 8 + + 73%
    - 20h 0 - 0 + 0%
    + 4 visits 0 - 00:00:00 + 0%
    + 5 visits - 0% + 0 0% @@ -1582,21 +2366,31 @@
    - 21h 0 - 0 + 0%
    + 7 visits 0 - 00:00:00 + 0%
    + 8 visits - 0% + 0 0% @@ -1605,21 +2399,31 @@
    - 22h 0 - 0 + 0%
    + 15-25 visits 0 - 00:00:00 + 0%
    + 26-50 visits - 0% + 0 0% @@ -1628,21 +2432,31 @@
    - 23h 0 - 0 + 0%
    + 101-200 visits 0 - 00:00:00 + 0%
    + 201+ visits - 0% + 0 0% @@ -1654,8 +2468,8 @@ Back to top -

    - Visits by Day of Week +

    + Visits by days since last visit

    @@ -1663,187 +2477,217 @@ - - - - - + New visits + + + + - + + + + + + + + + + + + - - - - - + 4 days + 5 days - - - - - + 6 days - - - - - + 7 days + + + + - - - + + + + + 31-60 days + + + + + + + + + + + + + + +
    -  Day of the week   +  Visits by days since last visit    Visits   - -  Actions   - -  Actions per Visit   - -  Avg. Time on Website   - -  Bounce Rate   - -  Conversion Rate  
    - Monday 2
    + 0 days - 6 - - 3 + 1
    + 1 day - 00:07:31 + 0
    + 2 days - 50% + 1
    + 3 days - 0% + 1
    - Tuesday - 2 - - 10 - - 5 - - 00:15:01 - - 0% - - 0% + 1
    - Wednesday 1 - 5 - - 5 - - 00:15:01 - - 0% - - 0% -
    - Thursday 1 - 5 - - 5 - - 00:15:01 - - 0% - - 0% -
    - Friday 1
    + 8-14 days - 5 - - 5 - - 00:15:01 - - 0% + 2
    + 15-30 days - 0% + 0
    - Saturday - 1 + 0
    + 61-120 days - 5 + 0
    + 121-364 days - 5 + 0
    + 365+ days - 00:15:01 + 0
    +
    + + Back to top + +

    + Returning Visits +

    + + + + + + + + + + + + + + + + + Returning Visits + + + + + + + + + + + + + + + + + + + + @@ -1852,8 +2696,8 @@ Back to top -

    - Screen Resolution +

    + Visits per local time

    @@ -1861,7 +2705,7 @@
    +  Name   + +  Value   +
    + Unique returning visitors - 0% + 2
    + Returning Users - 0% + 0
    - Sunday - 3 + 9
    + Actions by Returning Visits - 7 + 41
    + Maximum actions in one returning visit - 2.3 + 5
    + Bounce Rate for Returning Visits - 00:05:00 + 11%
    + Avg. Actions per Returning Visit - 67% + 4.6
    + Avg. Duration of a Returning Visit (in sec) - 0% + 00:13:21
    + 0h + 1h - -
    -  Resolution   +  Local time    Visits   @@ -1886,21 +2730,21 @@
    - 800x300 - 9 + 0 - 41 + 0 - 4.6 + 0 - 00:13:21 + 00:00:00 - 11% + 0% 0% @@ -1909,98 +2753,67 @@
    - 1024x768 - 2 + 0 - 2 + 0 - 1 + 0 00:00:00 - 100% + 0% 0%
    -
    - - Back to top - -

    - Browser Plugins -

    - - - - - - - - - - - + + 2h + + + + + 3h - - - - - - - - + 4h + + + + @@ -2022,12 +2845,22 @@ + 5h + + + + @@ -2035,12 +2868,22 @@ + 6h + + + + @@ -2048,12 +2891,22 @@ + 7h + + + + @@ -2061,12 +2914,22 @@ + 8h + + + + @@ -2074,68 +2937,41 @@ + 9h + + + + - -
    -  Plugin   - -  Visits   - -  % Visits   -
    - -   - Cookie - 11 + 0 - 100% + 0 + + 0 + + 00:00:00 + + 0% + + 0%
    - -   - Flash - 11 + 0 - 100% + 0
    - -   - Java - 11 + 0 - 100% + 00:00:00
    - -   - Director - 0 + 0% 0% @@ -2009,12 +2822,22 @@
    - -   - Gears + 0 + + 0 + 0 + 00:00:00 + + 0% + 0%
    - -   - Pdf + 0 + + 0 + 0 + 00:00:00 + + 0% + 0%
    - -   - Quicktime + 0 + + 0 + 0 + 00:00:00 + + 0% + 0%
    - -   - Realplayer + 0 + + 0 + 0 + 00:00:00 + + 0% + 0%
    - -   - Silverlight + 0 + + 0 + 0 + 00:00:00 + + 0% + 0%
    - -   - Windowsmedia + 0 + + 0 + 0 + 00:00:00 + + 0% + 0%
    -
    - - Back to top - -

    - Visitor Configuration -

    - - - - - - - - - - - - - - - + + 10h + 11h + 12h - -
    -  Configuration   - -  Visits   - -  Actions   - -  Actions per Visit   - -  Avg. Time on Website   - -  Bounce Rate   - -  Conversion Rate   -
    - Unknown / Unknown / 800x300 - 8 + 0 - 40 + 0 - 5 + 0 - 00:15:01 + 00:00:00 0% @@ -2147,21 +2983,21 @@
    - Windows / Firefox / 1024x768 - 2 + 0 - 2 + 0 - 1 + 0 00:00:00 - 100% + 0% 0% @@ -2170,78 +3006,41 @@
    - Windows / Opera / 800x300 - 1 + 11 - 1 + 43 - 1 + 3.9 - 00:00:00 + 00:10:55 - 100% + 27% 0%
    -
    - - Back to top - -

    - Browser language -

    - - - - - - - - - - - - - - - - + + + 13h - + + 14h - -
    -  Language   - -  Visits   - -  Actions   - -  Actions per Visit   - -  Avg. Time on Website   - -  Bounce Rate   - -  Conversion Rate   -
    - Unknown - 8 + 0 - 40 + 0 - 5 + 0 - 00:15:01 + 00:00:00 0% @@ -2251,80 +3050,43 @@
    - French - 3 + 0 - 3 + 0 - 1 + 0 00:00:00 - 100% + 0% 0%
    -
    - - Back to top - -

    - Language code -

    - - - - - - - - - - - - - - - - + + + 15h - + + 16h - - - -
    -  Language   - -  Visits   - -  Actions   - -  Actions per Visit   - -  Avg. Time on Website   - -  Bounce Rate   - -  Conversion Rate   -
    - Unknown (xx) - 8 + 0 - 40 + 0 - 5 + 0 - 00:15:01 + 00:00:00 0% @@ -2334,257 +3096,187 @@
    - French (fr) - 3 + 0 - 3 + 0 - 1 + 0 00:00:00 - 100% - 0%
    -
    - - Back to top - -

    - Actions - Main metrics -

    - - - - - - - - - - - - + 17h - - - - - - - - + + + + 18h - - - - - - - - + + + + 19h - - - - + + + + - -
    -  Name   - -  Value   -
    - Pageviews - 43 + 0%
    - Unique Pageviews - 27 + 0
    - Downloads 0
    - Unique Downloads 0 + 00:00:00 + + 0% + + 0% +
    - Outlinks 0
    - Unique Outlinks 0
    - Searches 0 + 00:00:00 + + 0% + + 0% +
    - Unique Keywords 0
    - Avg. generation time - 0.3s + 0 + + 0 + + 00:00:00 + + 0% + + 0%
    -
    - - Back to top - -

    - Page URLs -

    - - - - - - - - - - - - - - - + + 20h + 21h + 22h + 23h @@ -2593,8 +3285,8 @@ Back to top -

    - Entry pages +

    + Visits per server time

    @@ -2602,217 +3294,178 @@
    -  Page URL   - -  Pageviews   - -  Unique Pageviews   - -  Avg. time on page   - -  Bounce Rate   - -  Exit rate   - -  Avg. generation time   -
    - - /index.htm - - 9 + 0 - 9 + 0 - 00:05:20 + 0 - 11% + 00:00:00 - 11% + 0% - 0.3s + 0%
    - - Page URL not defined - - 17 + 0 - 9 + 0 - 00:00:00 + 0 - 0% + 00:00:00 0% - 0.22s + 0%
    - - /thankyou - - 16 + 0 - 8 + 0 - 00:06:00 + 0 - 0% + 00:00:00 - 100% + 0% - 0.31s + 0%
    - - /products - - 1 + 0 - 1 + 0 - 00:00:00 + 0 - 100% + 00:00:00 - 100% + 0% - 0.15s + 0%
    + + + 0h + + + 1h + + - -
    -  Entry Page URL   +  Server time   -  Entrances   +  Visits   -  Bounces   +  Actions   + +  Actions per Visit   + +  Avg. Time on Website    Bounce Rate   -  Avg. generation time   +  Revenue  
    - - /index.htm - - 9 + 1 1 - 11% + 1 - 0.3s + 00:00:00 + + 100% + + $ 0
    - - /products - - 1 + 0 - 1 + 0 - 100% + 0 - 0.15s + 00:00:00 + + 0% + + $ 0
    -
    - - Back to top - -

    - Exit pages -

    - - - - - - - - - - - - - + + 2h + + + 3h + + + 4h + + - -
    -  Exit Page URL   - -  Exits   - -  Unique Pageviews   - -  Exit rate   - -  Avg. generation time   -
    - - /index.htm - - 1 + 0 - 9 + 0 - 11% + 0 - 0.3s + 00:00:00 + + 0% + + $ 0
    - - /thankyou - - 8 + 0 - 8 + 0 - 100% + 0 - 0.31s + 00:00:00 + + 0% + + $ 0
    - - /products - - 1 + 0 - 1 + 0 - 100% + 0 - 0.15s + 00:00:00 + + 0% + + $ 0
    -
    - - Back to top - -

    - Page titles -

    - - - - - - - - - - - - - - - - + + + 5h - + + 6h + + + + + + + + + + + 8h + 9h - -
    -  Page Name   - -  Pageviews   - -  Unique Pageviews   - -  Avg. time on page   - -  Bounce Rate   - -  Exit rate   - -  Avg. generation time   -
    - second visitor - 16 + 0 - 16 + 0 - 00:07:30 + 0 - 0% + 00:00:00 0% - 0.25s + $ 0
    - Checkout - 8 + 0 - 8 + 0 + + 0 00:00:00 @@ -2821,303 +3474,188 @@ 0% - 100% + $ 0 +
    + 7h + 0 - 0.45s + 0 + + 0 + + 00:00:00 + + 0% + + $ 0
    - first page view - 2 + 0 - 2 + 0 - 00:00:00 + 0 - 100% + 00:00:00 - 100% + 0% - 0.14s + $ 0
    - Page Name not defined - 1 + 0 - 1 + 0 - 00:00:00 + 0 - 0% + 00:00:00 0% - 0.22s + $ 0
    -
    - - Back to top - -

    - Entry page titles -

    - - - - - - - - - - - - - + + 10h + + + 11h + + - -
    -  Entry Page title   - -  Entrances   - -  Bounces   - -  Bounce Rate   - -  Avg. generation time   -
    - second visitor - 8 + 0 + + 0 0 + 00:00:00 + 0% - 0.25s + $ 0
    - first page view - 2 + 8 - 2 + 40 - 100% + 5 - 0.14s + 00:15:01 + + 0% + + $ 0
    -
    - - Back to top - -

    - Exit page titles -

    - - - - - - - - - - - - - + + 12h + + + 13h + + - -
    -  Exit Page Title   - -  Exits   - -  Unique Pageviews   - -  Exit rate   - -  Avg. generation time   -
    - Checkout - 8 + 1 - 8 + 1 + + 1 + + 00:00:00 100% - 0.45s + $ 0
    - first page view - 2 + 0 - 2 + 0 - 100% + 0 - 0.14s + 00:00:00 + + 0% + + $ 0
    -
    - - Back to top - - - - There is no data for this report. -

    - Downloads -

    - - There is no data for this report. -

    - Content Name -

    - - There is no data for this report. -

    - Content Piece -

    - - There is no data for this report. -

    - Event Categories -

    - - There is no data for this report. -

    - Event Actions -

    - - There is no data for this report. -

    - Event Names -

    - - There is no data for this report. -

    - Site Search Keywords -

    - - There is no data for this report. -

    - Search Keywords with No Results -

    - - There is no data for this report. -

    - Search Categories -

    - - There is no data for this report. -

    - Pages Following a Site Search -

    - - There is no data for this report. -

    - Page Titles Following a Site Search -

    - - There is no data for this report. -

    - Referrer Type -

    - - - - - - - - - - - - - - - + + 14h + 15h + 16h - -
    -  Referrer Type   - -  Visits   - -  Actions   - -  Actions per Visit   - -  Avg. Time on Website   - -  Bounce Rate   - -  Revenue   -
    - Websites - 6 + 0 - 22 + 0 - 3.7 + 0 - 00:10:01 + 00:00:00 - 33% + 0% $ 0 @@ -3126,18 +3664,18 @@
    - Campaigns - 4 + 0 - 20 + 0 - 5 + 0 - 00:15:01 + 00:00:00 0% @@ -3149,169 +3687,182 @@
    - Direct Entry - 1 + 0 - 1 + 0 - 1 + 0 00:00:00 - 100% + 0% $ 0
    -
    - - Back to top - -

    - All Referrers -

    - - - - - - - - - - - - - - - - + + + 17h + + + + + + + + + + + 19h + + + + + + + + + + - -
    -  Referrer   - -  Visits   - -  Actions   - -  Actions per Visit   - -  Avg. Time on Website   - -  Bounce Rate   - -  Conversion Rate   -
    - referrer.com - 6 + 0 - 22 + 0 - 3.7 + 0 - 00:10:01 + 00:00:00 - 33% + 0% + + $ 0 +
    + 18h + 0 + + 0 + + 0 + + 00:00:00 0% + $ 0 +
    - goal-matching-url-parameter - 4 + 0 - 20 + 0 - 5 + 0 - 00:15:01 + 00:00:00 0% + $ 0 +
    + 20h + 0 + + 0 + + 0 + + 00:00:00 + 0% + $ 0 +
    -
    - - Back to top - -

    - Keywords -

    - - There is no data for this report. -

    - Websites -

    - - - - - - - - - - - - - - - + + + + + + + + + + + + 22h + + + + + + + + + +
    -  Website   - -  Visits   - -  Actions   - -  Actions per Visit   - -  Avg. Time on Website   - -  Bounce Rate   - -  Revenue   -
    + 21h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + $ 0 +
    - referrer.com - 6 + 0 - 22 + 0 - 3.7 + 0 - 00:10:01 + 00:00:00 - 33% + 0% + + $ 0 +
    + 23h + 1 + + 1 + + 1 + + 00:00:00 + + 100% $ 0 @@ -3323,13 +3874,8 @@ Back to top -

    - Search Engines -

    - - There is no data for this report. -

    - Campaigns +

    + Visits by Day of Week

    @@ -3337,7 +3883,7 @@ + Monday + + + + + + + + + + - -
    -  Campaign   +  Day of the week    Visits   @@ -3355,19 +3901,42 @@  Bounce Rate   -  Revenue   +  Conversion Rate  
    - goal-matching-url-parameter - 4 + 2 - 20 + 6 + + 3 + + 00:07:31 + + 50% + + 0% +
    + Tuesday + 2 + + 10 5 @@ -3379,126 +3948,87 @@ 0% - $ 0 + 0%
    -
    - - Back to top - -

    - Social Networks -

    - - There is no data for this report. -

    - Goals -

    - - - - - - - - - - + + Wednesday + + + + + + Thursday + + + + + + Friday + + + + - - - - - -
    -  Name   - -  Value   -
    - Conversions - 0 + 1 + + 5 + + 5 + + 00:15:01 + + 0% + + 0%
    - Visits with Conversions - 0 + 1 + + 5 + + 5 + + 00:15:01 + + 0% + + 0%
    - Revenue - $ 0 + 1 + + 5 + + 5 + + 00:15:01 + + 0%
    - Conversion Rate 0%
    -
    - - Back to top - -

    - Visits to Conversion -

    - - There is no data for this report. -

    - Days to Conversion -

    - - There is no data for this report. -

    - Country -

    - - - - - - - - - - - - - - - - + + + Saturday - + + Sunday @@ -3544,8 +4072,8 @@ Back to top -

    - Continent +

    + Page URLs

    @@ -3553,60 +4081,111 @@
    -  Country   - -  Visits   - -  Actions   - -  Actions per Visit   - -  Avg. Time on Website   - -  Bounce Rate   - -  Revenue   -
    - -   - Unknown - 8 + 1 - 40 + 5 5 @@ -3510,32 +4040,30 @@ 0% - $ 0 + 0%
    - -   - France 3 - 3 + 7 - 1 + 2.3 - 00:00:00 + 00:05:00 - 100% + 67% - $ 0 + 0%
    + + /index.htm + + + Page URL not defined + + + + + + + + + + + + + + + + + + + + + @@ -3627,60 +4209,67 @@ Back to top -

    - Region -

    +

    + Entry pages +

    -  Continent   +  Page URL   -  Visits   +  Pageviews   -  Actions   +  Unique Pageviews   -  Actions per Visit   +  Avg. time on page   -  Avg. Time on Website   +  Bounce Rate   -  Bounce Rate   +  Exit rate   -  Revenue   +  Avg. generation time  
    - Unknown - 8 + 9 - 40 + 9 - 5 + 00:05:20 - 00:15:01 + 11% - 0% + 11% - $ 0 + 0.3s
    - Europe - 3 + 17 - 3 + 9 + + 00:00:00 + + 0% + + 0% + + 0.22s +
    + + /thankyou + + 16 + + 8 + + 00:06:00 + + 0% + + 100% + + 0.31s +
    + + /products + + 1 1 @@ -3618,7 +4197,10 @@ 100% - $ 0 + 100% + + 0.15s
    - - + + /index.htm + + + + + + + @@ -3689,8 +4278,8 @@ Back to top -

    - City +

    + Exit pages

    @@ -3698,51 +4287,77 @@
    -  Region   - -  Visits   - -  Actions   +  Entry Page URL   -  Actions per Visit   +  Entrances   -  Avg. Time on Website   +  Bounces    Bounce Rate   -  Revenue   +  Avg. generation time  
    - -   - Unknown - 11 + 9 - 43 + 1 - 3.9 + 11% - 00:10:55 + 0.3s +
    + + /products + + 1 - 27% + 1 - $ 0 + 100% + + 0.15s
    - - + + /index.htm + + + + + + + + + + + + + + + @@ -3751,13 +4366,8 @@ Back to top -

    - Custom Variables -

    - - There is no data for this report. -

    - Length of Visits +

    + Page titles

    @@ -3765,91 +4375,118 @@
    -  City   - -  Visits   - -  Actions   +  Exit Page URL   -  Actions per Visit   +  Exits   -  Avg. Time on Website   +  Unique Pageviews   -  Bounce Rate   +  Exit rate   -  Revenue   +  Avg. generation time  
    - -   - Unknown - 11 + 1 - 43 + 9 - 3.9 + 11% - 00:10:55 + 0.3s +
    + + /thankyou + + 8 - 27% + 8 - $ 0 + 100% + + 0.31s +
    + + /products + + 1 + + 1 + + 100% + + 0.15s
    + + + + + + second visitor - - - - - - - - - - - - - - - - + + Checkout - - - - - - - - + + + + first page view + + + + + + Page Name not defined + + + + + @@ -3858,517 +4495,68 @@ Back to top -

    - Pages per Visit +

    + Site Search Keywords

    - - -
    -  Visit duration   +  Page Name   -  Visits   +  Pageviews   + +  Unique Pageviews   + +  Avg. time on page   + +  Bounce Rate   + +  Exit rate   + +  Avg. generation time  
    - 0-10s - 3 + 16
    - 11-30s - 0 + 16
    - 31-60s - 0 + 00:07:30
    - 1-2 min - 0 + 0%
    - 2-4 min - 0 + 0% + + 0.25s
    - 4-7 min - 0 + 8
    - 7-10 min - 0 + 8
    - 10-15 min - 0 + 00:00:00 + + 0% + + 100% + + 0.45s
    - 15-30 min - 8 + 2 + + 2 + + 00:00:00 + + 100% + + 100% + + 0.14s
    - 30+ min - 0 + 1 + + 1 + + 00:00:00 + + 0% + + 0% + + 0.22s
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Pages per visit   - -  Visits   -
    - 1 page - 3 -
    - 2 pages - 0 -
    - 3 pages - 0 -
    - 4 pages - 0 -
    - 5 pages - 8 -
    - 6-7 pages - 0 -
    - 8-10 pages - 0 -
    - 11-14 pages - 0 -
    - 15-20 pages - 0 -
    - 21+ pages - 0 -
    -
    - - Back to top - -

    - Visits by Visit Number + There is no data for this report. +

    + Pages Following a Site Search

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Visits by Visit Number   - -  Visits   - -  % Visits   -
    - 1 visit - 3 - - 27% -
    - 2 visits - 8 - - 73% -
    - 3 visits - 0 - - 0% -
    - 4 visits - 0 - - 0% -
    - 5 visits - 0 - - 0% -
    - 6 visits - 0 - - 0% -
    - 7 visits - 0 - - 0% -
    - 8 visits - 0 - - 0% -
    - 9-14 visits - 0 - - 0% -
    - 15-25 visits - 0 - - 0% -
    - 26-50 visits - 0 - - 0% -
    - 51-100 visits - 0 - - 0% -
    - 101-200 visits - 0 - - 0% -
    - 201+ visits - 0 - - 0% -
    -
    - - Back to top - -

    - Visits by days since last visit + There is no data for this report. +

    + Search Keywords with No Results +

    + + There is no data for this report. +

    + Page Titles Following a Site Search +

    + + There is no data for this report. +

    + Search Categories

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Visits by days since last visit   - -  Visits   -
    - New visits - 2 -
    - 0 days - 1 -
    - 1 day - 0 -
    - 2 days - 1 -
    - 3 days - 1 -
    - 4 days - 1 -
    - 5 days - 1 -
    - 6 days - 1 -
    - 7 days - 1 -
    - 8-14 days - 2 -
    - 15-30 days - 0 -
    - 31-60 days - 0 -
    - 61-120 days - 0 -
    - 121-364 days - 0 -
    - 365+ days - 0 -
    -
    - - Back to top - -

    - Returning Visits + There is no data for this report. +

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Name   - -  Value   -
    - Unique returning visitors - 2 -
    - Returning Users - 0 -
    - Returning Visits - 9 -
    - Actions by Returning Visits - 41 -
    - Maximum actions in one returning visit - 5 -
    - Bounce Rate for Returning Visits - 11% -
    - Avg. Actions per Returning Visit - 4.6 -
    - Avg. Duration of a Returning Visit (in sec) - 00:13:21 -
    -
    - - Back to top - -

    - Device type + There is no data for this report. +

    + Downloads +

    + + There is no data for this report. +

    + Event Categories +

    + + There is no data for this report. +

    + Event Actions +

    + + There is no data for this report. +

    + Event Names +

    + + There is no data for this report. +

    + Content Name +

    + + There is no data for this report. +

    + Content Piece +

    + + There is no data for this report. +

    + Actions - Main metrics

    @@ -4376,76 +4564,83 @@ - - - - - - - - + Pageviews + + + + + + + + + Unique Downloads + + + + + + + + + + + + + + + + + + + + @@ -4454,8 +4649,8 @@ Back to top -

    - Visitor Browser +

    + Entry page titles

    @@ -4463,101 +4658,54 @@
    -  Device type   - -  Visits   - -  Actions   - -  Actions per Visit   - -  Avg. Time on Website   - -  Bounce Rate   +  Name   -  Conversion Rate   +  Value  
    - -   - Unknown - 8 - - 40 - - 5 - - 00:15:01 + 43
    + Unique Pageviews - 0% + 27
    + Downloads - 0% + 0
    - -   - Desktop - 3 + 0
    + Outlinks - 3 + 0
    + Unique Outlinks - 1 + 0
    + Searches - 00:00:00 + 0
    + Unique Keywords - 100% + 0
    + Avg. generation time - 0% + 0.3s
    - - + second visitor - - + first page view - - - - - - - - - - - - @@ -4566,8 +4714,8 @@ Back to top -

    - Device brand +

    + Exit page titles

    @@ -4575,111 +4723,54 @@
    -  Browser   - -  Visits   - -  Actions   +  Entry Page title   -  Actions per Visit   +  Entrances   -  Avg. Time on Website   +  Bounces    Bounce Rate   -  Conversion Rate   +  Avg. generation time  
    - -   - Unknown 8 - 40 - - 5 - - 00:15:01 + 0 0% - 0% + 0.25s
    - -   - Firefox 2 2 - 1 - - 00:00:00 - - 100% - - 0% -
    - -   - Opera - 1 - - 1 - - 1 - - 00:00:00 - 100% - 0% + 0.14s
    - - - - + Checkout - -
    -  Device brand   - -  Visits   - -  Actions   +  Exit Page Title   -  Actions per Visit   +  Exits   -  Avg. Time on Website   +  Unique Pageviews   -  Bounce Rate   +  Exit rate   -  Conversion Rate   +  Avg. generation time  
    - -   - Unknown - 11 - - 43 - - 3.9 + 8 - 00:10:55 + 8 - 27% + 100% - 0% + 0.45s
    -
    - - Back to top - -

    - Device model -

    - - - - - - - - - - - - - - - - + + - - + first page view @@ -4688,8 +4779,8 @@ Back to top -

    - Browser version +

    + Referrer Type

    @@ -4697,7 +4788,7 @@
    -  Device model   - -  Visits   - -  Actions   - -  Actions per Visit   - -  Avg. Time on Website   - -  Bounce Rate   - -  Conversion Rate   -
    - Unknown - 11 - - 43 - - 3.9 + 2 - 00:10:55 + 2 - 27% + 100% - 0% + 0.14s
    + Websites + Campaigns + Direct Entry @@ -4791,7 +4876,7 @@ 100% @@ -4800,8 +4885,8 @@ Back to top -

    - Operating System families +

    + All Referrers

    @@ -4809,7 +4894,7 @@
    -  Browser version   +  Referrer Type    Visits   @@ -4715,66 +4806,60 @@  Bounce Rate   -  Conversion Rate   +  Revenue  
    - -   - Unknown - 8 + 6 - 40 + 22 - 5 + 3.7 - 00:15:01 + 00:10:01 - 0% + 33% - 0% + $ 0
    - -   - Firefox 3.6 - 2 + 4 - 2 + 20 - 1 + 5 - 00:00:00 + 00:15:01 - 100% + 0% - 0% + $ 0
    - -   - Opera 9.63 1 - 0% + $ 0
    + referrer.com + goal-matching-url-parameter
    -  Operating system family   +  Referrer    Visits   @@ -4834,23 +4919,21 @@
    - -   - Unknown - 8 + 6 - 40 + 22 - 5 + 3.7 - 00:15:01 + 00:10:01 - 0% + 33% 0% @@ -4859,23 +4942,21 @@
    - -   - Windows - 3 + 4 - 3 + 20 - 1 + 5 - 00:00:00 + 00:15:01 - 100% + 0% 0% @@ -4887,8 +4968,18 @@ Back to top -

    - Operating System versions +

    + Keywords +

    + + There is no data for this report. +

    + Search Engines +

    + + There is no data for this report. +

    + Websites

    @@ -4896,7 +4987,7 @@ - - - - - - - - - - + referrer.com @@ -4974,8 +5038,13 @@ Back to top -

    - Browser engines +

    + Social Networks +

    + + There is no data for this report. +

    + Campaigns

    @@ -4983,7 +5052,7 @@
    -  Operating System versions   +  Website    Visits   @@ -4914,58 +5005,31 @@  Bounce Rate   -  Conversion Rate   +  Revenue  
    - -   - Unknown - 8 - - 40 - - 5 - - 00:15:01 - - 0% - - 0% -
    - -   - Windows XP - 3 + 6 - 3 + 22 - 1 + 3.7 - 00:00:00 + 00:10:01 - 100% + 33% - 0% + $ 0
    + goal-matching-url-parameter - - + +
    -  Browser engine   +  Campaign    Visits   @@ -5001,19 +5070,19 @@  Bounce Rate   -  Conversion Rate   +  Revenue  
    - Unknown - 8 + 4 - 40 + 20 5 @@ -5025,51 +5094,59 @@ 0% - 0% + $ 0
    +
    + + Back to top + +

    + Goals +

    + + + + + + + + + + + - - - - + Conversions + + + + - - - - + Revenue + + + + @@ -5080,5 +5157,35 @@ Back to top +

    + Visits to Conversion +

    + + There is no data for this report. +

    + Days to Conversion +

    + + There is no data for this report. +

    + Data tables +

    + + There is no data for this report. +

    + Temperatures evolution over time +

    + + There is no data for this report. +

    + Pie graph +

    + + There is no data for this report. +

    + Advanced tag cloud: with logos and links +

    + + There is no data for this report. \ No newline at end of file diff --git a/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getMetadata_day.xml b/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getMetadata_day.xml index 813c7c3279..439a50b51d 100644 --- a/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getMetadata_day.xml +++ b/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getMetadata_day.xml @@ -2,6 +2,7 @@ Visitors + Locations Country UserCountry getCountry 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 1b05d735d9..c450663aec 100644 --- a/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getProcessedReport_day.xml +++ b/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getProcessedReport_day.xml @@ -4,6 +4,7 @@ Sunday 4 January 2009 Visitors + Locations Country UserCountry getCountry 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 cec23aa081..75cc04d44b 100644 --- a/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getReportMetadata_day.xml +++ b/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getReportMetadata_day.xml @@ -67,7 +67,8 @@ MultiSites_getOne - Visits Summary + Visitors + Overview Visits Summary VisitsSummary get @@ -97,12 +98,13 @@ VisitsSummary_get - Visits Summary - Visits by Server Time - VisitTime - getVisitInformationPerServerTime - Server time - This graph shows what time it was in the <strong> server's time zone </strong> during the visits. + Visitors + Custom Variables + Custom Variables + CustomVariables + getCustomVariables + Custom Variable name + This report contains information about your Custom Variables. Click on a variable name to see the distribution of the values. <br /> For more information about Custom Variables in general, read the <a href="http://piwik.org/docs/custom-variables/" rel="noreferrer" target="_blank">Custom Variables documentation on piwik.org</a> Visits Unique visitors @@ -124,7 +126,7 @@ Avg. Time on Website Bounce Rate - 1 + getCustomVariablesValuesFromNameId Conversions Revenue @@ -132,16 +134,17 @@ Revenue per Visit - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=VisitTime&apiAction=getVisitInformationPerServerTime&period=day&date=2009-01-04 - VisitTime_getVisitInformationPerServerTime + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=CustomVariables&apiAction=getCustomVariables&period=day&date=2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=CustomVariables&apiAction=getCustomVariables&period=day&date=2008-12-06,2009-01-04 + CustomVariables_getCustomVariables - Visits Summary - Visits by Local Time - VisitTime - getVisitInformationPerLocalTime - Local time - This graph shows what time it was in the <strong> visitors' time zones </strong> during their visits. + Visitors + Devices + Device type + DevicesDetection + getType + Device type Visits Unique visitors @@ -164,17 +167,17 @@ Bounce Rate Conversion Rate - 1 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=VisitTime&apiAction=getVisitInformationPerLocalTime&period=day&date=2009-01-04 - VisitTime_getVisitInformationPerLocalTime + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=DevicesDetection&apiAction=getType&period=day&date=2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=DevicesDetection&apiAction=getType&period=day&date=2008-12-06,2009-01-04 + DevicesDetection_getType - Visits Summary - Visits by Day of Week - VisitTime - getByDayOfWeek - Day of the week - This graph shows the number of visits your website received on each day of the week. + Visitors + Devices + Device model + DevicesDetection + getModel + Device model Visits Unique visitors @@ -197,12 +200,46 @@ Bounce Rate Conversion Rate - 1 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=VisitTime&apiAction=getByDayOfWeek&period=day&date=2009-01-04 - VisitTime_getByDayOfWeek + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=DevicesDetection&apiAction=getModel&period=day&date=2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=DevicesDetection&apiAction=getModel&period=day&date=2008-12-06,2009-01-04 + DevicesDetection_getModel + + + Visitors + Devices + Device brand + DevicesDetection + getBrand + Device brand + + Visits + Unique visitors + Actions + Users + + + If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his 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 he visits 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 number of users logged in your website. It is the number of unique active users that have a User ID set (via the Tracking code function 'setUserId'). + 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 + + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=DevicesDetection&apiAction=getBrand&period=day&date=2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=DevicesDetection&apiAction=getBrand&period=day&date=2008-12-06,2009-01-04 + DevicesDetection_getBrand - Visitor Settings + Visitors + Devices Screen Resolution Resolution getResolution @@ -229,37 +266,65 @@ Bounce Rate Conversion Rate + + + Configurations + Resolution + getConfiguration + + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Resolution&apiAction=getResolution&period=day&date=2009-01-04 index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Resolution&apiAction=getResolution&period=day&date=2008-12-06,2009-01-04 Resolution_getResolution - Visitor Settings - Browser Plugins - DevicePlugins - getPlugin - Plugin - This report shows which browser plugins your visitors had enabled. This information might be important for choosing the right way to deliver your content. + Visitors + Software + Operating System versions + DevicesDetection + getOsVersions + Operating System versions Visits + Unique visitors + Actions + Users If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his 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 he visits 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 number of users logged in your website. It is the number of unique active users that have a User ID set (via the Tracking code function 'setUserId'). + 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. - % Visits + Actions per Visit + Avg. Time on Website + Bounce Rate + Conversion Rate - 1 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=DevicePlugins&apiAction=getPlugin&period=day&date=2009-01-04 - DevicePlugins_getPlugin + + + Operating System families + DevicesDetection + getOsFamilies + + + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=DevicesDetection&apiAction=getOsVersions&period=day&date=2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=DevicesDetection&apiAction=getOsVersions&period=day&date=2008-12-06,2009-01-04 + DevicesDetection_getOsVersions - Visitor Settings - Visitor Configuration - Resolution - getConfiguration - Configuration - This report shows the most common overall configurations that your visitors had. A configuration is the combination of an operating system, a browser type and a screen resolution. + Visitors + Software + Browsers + DevicesDetection + getBrowsers + Browser + This report contains information about what kind of browser your visitors were using. Each browser version is listed separately. Visits Unique visitors @@ -282,16 +347,24 @@ Bounce Rate Conversion Rate - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Resolution&apiAction=getConfiguration&period=day&date=2009-01-04 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Resolution&apiAction=getConfiguration&period=day&date=2008-12-06,2009-01-04 - Resolution_getConfiguration + + + Browser version + DevicesDetection + getBrowserVersions + + + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=DevicesDetection&apiAction=getBrowsers&period=day&date=2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=DevicesDetection&apiAction=getBrowsers&period=day&date=2008-12-06,2009-01-04 + DevicesDetection_getBrowsers - Visitor Settings - Browser language - UserLanguage - getLanguage - Language + Visitors + Software + Browser version + DevicesDetection + getBrowserVersions + Browser version Visits Unique visitors @@ -314,16 +387,25 @@ Bounce Rate Conversion Rate - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=UserLanguage&apiAction=getLanguage&period=day&date=2009-01-04 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=UserLanguage&apiAction=getLanguage&period=day&date=2008-12-06,2009-01-04 - UserLanguage_getLanguage + + + Browsers + DevicesDetection + getBrowsers + + + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=DevicesDetection&apiAction=getBrowserVersions&period=day&date=2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=DevicesDetection&apiAction=getBrowserVersions&period=day&date=2008-12-06,2009-01-04 + DevicesDetection_getBrowserVersions - Visitor Settings - Language code - UserLanguage - getLanguageCode - Language + Visitors + Software + Configurations + Resolution + getConfiguration + Configuration + This report shows the most common overall configurations that your visitors had. A configuration is the combination of an operating system, a browser type and a screen resolution. Visits Unique visitors @@ -346,284 +428,600 @@ Bounce Rate Conversion Rate - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=UserLanguage&apiAction=getLanguageCode&period=day&date=2009-01-04 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=UserLanguage&apiAction=getLanguageCode&period=day&date=2008-12-06,2009-01-04 - UserLanguage_getLanguageCode + + + Screen Resolution + Resolution + getResolution + + + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Resolution&apiAction=getConfiguration&period=day&date=2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Resolution&apiAction=getConfiguration&period=day&date=2008-12-06,2009-01-04 + Resolution_getConfiguration - API - Main metrics - API - get + Visitors + Software + Operating System families + DevicesDetection + getOsFamilies + Operating system family - Pageviews - Unique Pageviews - Downloads - Unique Downloads - Outlinks - Unique Outlinks - Searches - Unique Keywords - Conversions - Visits with Conversions - Revenue - Unique visitors Visits - Users + Unique visitors Actions - Maximum actions in one visit - Returning Visits - Actions by Returning Visits - Unique returning visitors - Returning Users - Maximum actions in one returning visit + Users - The number of times this page was visited. - The number of visits that included this page. If a page was viewed multiple times during one visit, it is only counted once. - The number of times this link was clicked. - The number of visits that involved a click on this link. If a link was clicked multiple times during one visit, it is only counted once. - The number of times this link was clicked. - The number of visits that involved a click on this link. If a link was clicked multiple times during one visit, it is only counted once. - The number of visits that searched for this keyword on your website's search engine. - The number of unduplicated visitors coming to your website. Every user is only counted once, even if he visits the website multiple times a day. If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit. - The number of users logged in your website. It is the number of unique active users that have a User ID set (via the Tracking code function 'setUserId'). + The number of unduplicated visitors coming to your website. Every user is only counted once, even if he visits 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 time it took to generate the page. This metric includes the time it took the server to generate the web page, plus the time it took for the visitor to download the response from the server. A lower 'Avg. generation time' means a faster website for your visitors! - The percentage of visits that triggered a goal conversion. - The percentage of visits that only had a single pageview. This means, that the visitor left the website directly from the entrance page. + The number of users logged in your website. It is the number of unique active users that have a User ID set (via the Tracking code function 'setUserId'). 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. - Avg. generation time - Conversion Rate - Bounce Rate Actions per Visit - Avg. Visit Duration (in seconds) - Avg. Duration of a Returning Visit (in sec) - Avg. Actions per Returning Visit - Bounce Rate for Returning Visits + Avg. Time on Website + Bounce Rate + Conversion Rate - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=API&apiAction=get&period=day&date=2008-12-06,2009-01-04 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=API&apiAction=get&period=day&date=2008-12-06,2009-01-04 - API_get + + + Operating System versions + DevicesDetection + getOsVersions + + + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=DevicesDetection&apiAction=getOsFamilies&period=day&date=2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=DevicesDetection&apiAction=getOsFamilies&period=day&date=2008-12-06,2009-01-04 + DevicesDetection_getOsFamilies - Ecommerce - Ecommerce Orders - Goals - get - - ecommerceOrder - + Visitors + Software + Browser engines + DevicesDetection + getBrowserEngines + Browser engine + This report shows your visitors' browsers broken down into browser engines. <br /> The most important information for web developers is what kind of rendering engine their visitors are using. The labels contain the names of the engines followed by the most common browser using that engine in brackets. - Ecommerce Orders - Visits with Conversions - Conversion Rate - Revenue - Subtotal - Tax - Shipping - Discount - Purchased Products + Visits + Unique visitors + Actions + Users + If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his 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 he visits 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 number of users logged in your website. It is the number of unique active users that have a User ID set (via the Tracking code function 'setUserId'). + 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. - Average Order Value - - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=get&idGoal=ecommerceOrder&period=day&date=2008-12-06,2009-01-04 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=get&idGoal=ecommerceOrder&period=day&date=2008-12-06,2009-01-04 - Goals_get_idGoal--ecommerceOrder + Actions per Visit + Avg. Time on Website + Bounce Rate + Conversion Rate + + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=DevicesDetection&apiAction=getBrowserEngines&period=day&date=2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=DevicesDetection&apiAction=getBrowserEngines&period=day&date=2008-12-06,2009-01-04 + DevicesDetection_getBrowserEngines - Ecommerce - Ecommerce Orders - Visits to Conversion - Goals - getVisitsUntilConversion - - ecommerceOrder - - Visits to Conversion + Visitors + Software + Browser Plugins + DevicePlugins + getPlugin + Plugin + This report shows which browser plugins your visitors had enabled. This information might be important for choosing the right way to deliver your content. - Conversions + Visits + + If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit. + + + % Visits + 1 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=getVisitsUntilConversion&idGoal=ecommerceOrder&period=day&date=2009-01-04 - Goals_getVisitsUntilConversion_idGoal--ecommerceOrder + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=DevicePlugins&apiAction=getPlugin&period=day&date=2009-01-04 + DevicePlugins_getPlugin - Ecommerce - Ecommerce Orders - Days to Conversion - Goals - getDaysToConversion - - ecommerceOrder - - Days to Conversion + Visitors + Locations + Country + UserCountry + getCountry + Country + This report shows which country your visitors were in when they accessed your website. + Visits + Unique visitors + Actions + + + If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his 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 he visits 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 + + Conversions + Revenue + + + Revenue per Visit + + 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 + + + Visitors + Locations + Continent + UserCountry + getContinent + Continent + This report shows which continent your visitors were in when they accessed your website. + + Visits + Unique visitors + Actions - 1 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=getDaysToConversion&idGoal=ecommerceOrder&period=day&date=2009-01-04 - Goals_getDaysToConversion_idGoal--ecommerceOrder + + If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his 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 he visits 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 + + + Conversions + Revenue + + + Revenue per Visit + + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=UserCountry&apiAction=getContinent&period=day&date=2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=UserCountry&apiAction=getContinent&period=day&date=2008-12-06,2009-01-04 + UserCountry_getContinent - Ecommerce - Abandoned Carts - Goals - get - - ecommerceAbandonedCart - + Visitors + Locations + Region + UserCountry + getRegion + Region + This report shows which region your visitors were in when they accessed your website.<br/>In order to see data for this report, you must setup GeoIP in the Geolocation admin tab. The commercial <a rel="noreferrer" target="_blank" href="http://www.maxmind.com/?rId=piwik">Maxmind</a> GeoIP databases are more accurate than the free ones. To see how accurate they are, click <a rel="noreferrer" target="_blank" href="http://www.maxmind.com/en/city_accuracy?rId=piwik">here</a>. - Abandoned Carts - Conversion Rate - Revenue left in cart - Products left in cart + Visits + Unique visitors + Actions + If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his 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 he visits 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. - Average Order Value + Actions per Visit + Avg. Time on Website + Bounce Rate - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=get&idGoal=ecommerceAbandonedCart&period=day&date=2008-12-06,2009-01-04 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=get&idGoal=ecommerceAbandonedCart&period=day&date=2008-12-06,2009-01-04 - Goals_get_idGoal--ecommerceAbandonedCart + + Conversions + Revenue + + + Revenue per Visit + + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=UserCountry&apiAction=getRegion&period=day&date=2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=UserCountry&apiAction=getRegion&period=day&date=2008-12-06,2009-01-04 + UserCountry_getRegion - Ecommerce - Abandoned Carts - Visits to Conversion - Goals - getVisitsUntilConversion - - ecommerceAbandonedCart - - Visits to Conversion + Visitors + Locations + Browser language + UserLanguage + getLanguage + Language + Visits + Unique visitors + Actions + Users + + + If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his 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 he visits 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 number of users logged in your website. It is the number of unique active users that have a User ID set (via the Tracking code function 'setUserId'). + 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 + + + + Language code + UserLanguage + getLanguageCode + + + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=UserLanguage&apiAction=getLanguage&period=day&date=2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=UserLanguage&apiAction=getLanguage&period=day&date=2008-12-06,2009-01-04 + UserLanguage_getLanguage + + + Visitors + Locations + City + UserCountry + getCity + City + This report shows the cities your visitors were in when they accessed your website.<br/>In order to see data for this report, you must setup GeoIP in the Geolocation admin tab. The commercial <a rel="noreferrer" target="_blank" href="http://www.maxmind.com/?rId=piwik">Maxmind</a> GeoIP databases are more accurate than the free ones. To see how accurate they are, click <a rel="noreferrer" target="_blank" href="http://www.maxmind.com/en/city_accuracy?rId=piwik">here</a>. + + Visits + Unique visitors + Actions + + + If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his 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 he visits 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 + + Conversions + Revenue + + + Revenue per Visit + + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=UserCountry&apiAction=getCity&period=day&date=2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=UserCountry&apiAction=getCity&period=day&date=2008-12-06,2009-01-04 + UserCountry_getCity + + + Visitors + Locations + Language code + UserLanguage + getLanguageCode + Language + + Visits + Unique visitors + Actions + Users + + + If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his 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 he visits 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 number of users logged in your website. It is the number of unique active users that have a User ID set (via the Tracking code function 'setUserId'). + 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 + + + + Browser language + UserLanguage + getLanguage + + + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=UserLanguage&apiAction=getLanguageCode&period=day&date=2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=UserLanguage&apiAction=getLanguageCode&period=day&date=2008-12-06,2009-01-04 + UserLanguage_getLanguageCode + + + Visitors + Locations + Provider + Provider + getProvider + Provider + This report shows which Internet Service Providers your visitors used to access the website. You can click on a provider name for more details. <br /> If Piwik can't determine a visitor's provider, it is listed as IP. + + Visits + Unique visitors + Actions + Users + + If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his 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 he visits 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 number of users logged in your website. It is the number of unique active users that have a User ID set (via the Tracking code function 'setUserId'). + 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 + + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Provider&apiAction=getProvider&period=day&date=2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Provider&apiAction=getProvider&period=day&date=2008-12-06,2009-01-04 + Provider_getProvider + + + Visitors + Engagement + Length of Visits + VisitorInterest + getNumberOfVisitsPerVisitDuration + Visit duration + In this report, you can see how many visits had a certain total duration. Initially, the report is shown as a tag cloud, more common durations are displayed in a larger font.<br />Please note, that you can view the report in other ways than as a tag cloud. Use the controls at the bottom of the report to do so. + + Visits + + + If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit. + 1 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=getVisitsUntilConversion&idGoal=ecommerceAbandonedCart&period=day&date=2009-01-04 - Goals_getVisitsUntilConversion_idGoal--ecommerceAbandonedCart + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=VisitorInterest&apiAction=getNumberOfVisitsPerVisitDuration&period=day&date=2009-01-04 + VisitorInterest_getNumberOfVisitsPerVisitDuration - Ecommerce - Abandoned Carts - Days to Conversion - Goals - getDaysToConversion - - ecommerceAbandonedCart - - Days to Conversion + Visitors + Engagement + Pages per Visit + VisitorInterest + getNumberOfVisitsPerPage + Pages per visit + In this report, you can see how many visits involved a certain number of pageviews. Initially, the report is shown as a tag cloud, more common numbers of pages are displayed in a larger font.<br />Please note, that you can view the report in other ways than as a tag cloud. Use the controls at the bottom of the report to do so. - Conversions + Visits + + If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit. + 1 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=getDaysToConversion&idGoal=ecommerceAbandonedCart&period=day&date=2009-01-04 - Goals_getDaysToConversion_idGoal--ecommerceAbandonedCart + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=VisitorInterest&apiAction=getNumberOfVisitsPerPage&period=day&date=2009-01-04 + VisitorInterest_getNumberOfVisitsPerPage - Ecommerce - Product SKU - Goals - getItemsSku - Product SKU + Visitors + Engagement + Visits by Visit Number + VisitorInterest + getNumberOfVisitsByVisitCount + Visits by Visit Number + In this report, you can see the number of visits who were the Nth visit, ie. visitors who visited your website at least N times.<br />Please note, that you can view the report in other ways than as a tag cloud. Use the controls at the bottom of the report to do so. - Product Revenue - Quantity - Unique Purchases Visits + + If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit. + - Average Price - Average Quantity - Product Conversion Rate + % Visits - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=getItemsSku&period=day&date=2009-01-04 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=getItemsSku&period=day&date=2008-12-06,2009-01-04 - Goals_getItemsSku + 1 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=VisitorInterest&apiAction=getNumberOfVisitsByVisitCount&period=day&date=2009-01-04 + VisitorInterest_getNumberOfVisitsByVisitCount - Ecommerce - Product Name - Goals - getItemsName - Product Name + Visitors + Engagement + Visits by days since last visit + VisitorInterest + getNumberOfVisitsByDaysSinceLast + Visits by days since last visit + In this report, you can see how many visits were from visitors whose last visit was a certain number of days ago. - Product Revenue - Quantity - Unique Purchases Visits + + If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit. + + 1 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=VisitorInterest&apiAction=getNumberOfVisitsByDaysSinceLast&period=day&date=2009-01-04 + VisitorInterest_getNumberOfVisitsByDaysSinceLast + + + Visitors + Engagement + Returning Visits + VisitFrequency + get + + Returning Visits + Actions by Returning Visits + Unique returning visitors + Returning Users + Maximum actions in one returning visit + - Average Price - Average Quantity - Product Conversion Rate + Avg. Duration of a Returning Visit (in sec) + Avg. Actions per Returning Visit + Bounce Rate for Returning Visits + + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=VisitFrequency&apiAction=get&period=day&date=2008-12-06,2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=VisitFrequency&apiAction=get&period=day&date=2008-12-06,2009-01-04 + VisitFrequency_get + + + Visitors + Times + Visits per local time + VisitTime + getVisitInformationPerLocalTime + Local time + This graph shows what time it was in the <strong> visitors' time zones </strong> during their visits. + + Visits + Unique visitors + Actions + Users + + + If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his 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 he visits 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 number of users logged in your website. It is the number of unique active users that have a User ID set (via the Tracking code function 'setUserId'). + 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 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=getItemsName&period=day&date=2009-01-04 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=getItemsName&period=day&date=2008-12-06,2009-01-04 - Goals_getItemsName + 1 + + + Visits by Day of Week + VisitTime + getByDayOfWeek + + + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=VisitTime&apiAction=getVisitInformationPerLocalTime&period=day&date=2009-01-04 + VisitTime_getVisitInformationPerLocalTime - Ecommerce - Product Category - Goals - getItemsCategory - Product Category + Visitors + Times + Visits per server time + VisitTime + getVisitInformationPerServerTime + Server time + This graph shows what time it was in the <strong> server's time zone </strong> during the visits. - Product Revenue - Quantity - Unique Purchases Visits + Unique visitors + Actions + Users + + If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his 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 he visits 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 number of users logged in your website. It is the number of unique active users that have a User ID set (via the Tracking code function 'setUserId'). + 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. + - Average Price - Average Quantity - Product Conversion Rate + Actions per Visit + Avg. Time on Website + Bounce Rate - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=getItemsCategory&period=day&date=2009-01-04 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=getItemsCategory&period=day&date=2008-12-06,2009-01-04 - Goals_getItemsCategory + 1 + + Conversions + Revenue + + + Revenue per Visit + + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=VisitTime&apiAction=getVisitInformationPerServerTime&period=day&date=2009-01-04 + VisitTime_getVisitInformationPerServerTime - Actions - Actions - Main metrics - Actions - get + Visitors + Times + Visits by Day of Week + VisitTime + getByDayOfWeek + Day of the week + This graph shows the number of visits your website received on each day of the week. - Pageviews - Unique Pageviews - Downloads - Unique Downloads - Outlinks - Unique Outlinks - Searches - Unique Keywords + Visits + Unique visitors + Actions + Users - The number of times this page was visited. - The number of visits that included this page. If a page was viewed multiple times during one visit, it is only counted once. - The number of times this link was clicked. - The number of visits that involved a click on this link. If a link was clicked multiple times during one visit, it is only counted once. - The number of times this link was clicked. - The number of visits that involved a click on this link. If a link was clicked multiple times during one visit, it is only counted once. - The number of visits that searched for this keyword on your website's search engine. - The average time it took to generate the page. This metric includes the time it took the server to generate the web page, plus the time it took for the visitor to download the response from the server. A lower 'Avg. generation time' means a faster website for your visitors! + If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his 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 he visits 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 number of users logged in your website. It is the number of unique active users that have a User ID set (via the Tracking code function 'setUserId'). + 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. - Avg. generation time + Actions per Visit + Avg. Time on Website + Bounce Rate + Conversion Rate - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=get&period=day&date=2008-12-06,2009-01-04 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=get&period=day&date=2008-12-06,2009-01-04 - Actions_get + 1 + + + Visits per local time + VisitTime + getVisitInformationPerLocalTime + + + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=VisitTime&apiAction=getByDayOfWeek&period=day&date=2009-01-04 + VisitTime_getByDayOfWeek Actions + Pages Page URLs Actions getPageUrls @@ -654,6 +1052,7 @@ Actions + Entry pages Entry pages Actions getEntryPageUrls @@ -674,12 +1073,20 @@ Avg. generation time getEntryPageUrls + + + Entry page titles + Actions + getEntryPageTitles + + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getEntryPageUrls&period=day&date=2009-01-04 index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getEntryPageUrls&period=day&date=2008-12-06,2009-01-04 Actions_getEntryPageUrls Actions + Exit pages Exit pages Actions getExitPageUrls @@ -702,12 +1109,20 @@ Avg. generation time getExitPageUrls + + + Exit page titles + Actions + getExitPageTitles + + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getExitPageUrls&period=day&date=2009-01-04 index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getExitPageUrls&period=day&date=2008-12-06,2009-01-04 Actions_getExitPageUrls Actions + Page titles Page titles Actions getPageTitles @@ -732,64 +1147,147 @@ Avg. generation time getPageTitles + + + Entry page titles + Actions + getEntryPageTitles + + + Exit page titles + Actions + getExitPageTitles + + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getPageTitles&period=day&date=2009-01-04 index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getPageTitles&period=day&date=2008-12-06,2009-01-04 Actions_getPageTitles Actions - Entry page titles + Site Search + Site Search Keywords Actions - getEntryPageTitles - Entry Page title - This report contains information about the titles of entry pages that were used during the specified period. Use the plus and minus icons on the left to navigate. + getSiteSearchKeywords + Keyword + This report lists the Search Keywords that visitors searched for on your internal Search Engine.<br/><br/>Tracking searches that visitors make on your website is a very effective way to learn more about what your audience is looking for, it can help find ideas for new content, new Ecommerce products that potential customers might be searching for, and generally improve the visitors' experience on your website.<br/><br/><a href="http://piwik.org/docs/site-search/" rel="noreferrer" target="_blank">Learn more about Tracking how your visitors use your Search engine.</a> - Entrances - Bounces + Searches + Search Results pages - Number of visits that started on this page. - Number of visits that started and ended on this page. This means that the visitor left the website after viewing only this page. - The percentage of visits that started on this page and left the website straight away. - The average time it took to generate the page. This metric includes the time it took the server to generate the web page, plus the time it took for the visitor to download the response from the server. A lower 'Avg. generation time' means a faster website for your visitors! + The number of visits that searched for this keyword on your website's search engine. + Visitors will search on your website, and sometimes click "next" to view more results. This is the average number of search results pages viewed for this keyword. + The percentage of visits that left the website after searching for this Keyword on your Site Search engine. - Bounce Rate - Avg. generation time + % Search Exits - getEntryPageTitles - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getEntryPageTitles&period=day&date=2009-01-04 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getEntryPageTitles&period=day&date=2008-12-06,2009-01-04 - Actions_getEntryPageTitles + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getSiteSearchKeywords&period=day&date=2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getSiteSearchKeywords&period=day&date=2008-12-06,2009-01-04 + Actions_getSiteSearchKeywords Actions - Exit page titles + Site Search + Pages Following a Site Search Actions - getExitPageTitles - Exit Page Title - This report contains information about the titles of exit pages that occurred during the specified period. Use the plus and minus icons on the left to navigate. + getPageUrlsFollowingSiteSearch + Destination Page + When visitors search on your website, they are looking for a particular page, content, product, or service. This report lists the pages that were clicked the most after an internal search. In other words, the list of pages the most searched for by visitors already on your website.<br/>Use the plus and minus icons on the left to navigate. - Exits - Unique Pageviews + Clicked in search results + Total Pageviews - Number of visits that ended on this page. - The number of visits that included this page. If a page was viewed multiple times during one visit, it is only counted once. - The percentage of visits that left the website after viewing this page. - The average time it took to generate the page. This metric includes the time it took the server to generate the web page, plus the time it took for the visitor to download the response from the server. A lower 'Avg. generation time' means a faster website for your visitors! + 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. + + + + Page Titles Following a Site Search + Actions + getPageTitlesFollowingSiteSearch + + + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getPageUrlsFollowingSiteSearch&period=day&date=2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getPageUrlsFollowingSiteSearch&period=day&date=2008-12-06,2009-01-04 + Actions_getPageUrlsFollowingSiteSearch + + + Actions + Site Search + Search Keywords with No Results + Actions + getSiteSearchNoResultKeywords + Keyword with No Search Result + Tracking searches that visitors make on your website is a very effective way to learn more about what your audience is looking for, it can help find ideas for new content, new Ecommerce products that potential customers might be searching for, and generally improve the visitors' experience on your website.<br /><br />This report lists the Search Keywords that did not return any Search result: maybe the search engine algorithm can be improved, or maybe your visitors are looking for content that is not (yet) on your website? + + Searches + + + The number of visits that searched for this keyword on your website's search engine. + The percentage of visits that left the website after searching for this Keyword on your Site Search engine. - Exit rate - Avg. generation time + % Search Exits - getExitPageTitles - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getExitPageTitles&period=day&date=2009-01-04 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getExitPageTitles&period=day&date=2008-12-06,2009-01-04 - Actions_getExitPageTitles + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getSiteSearchNoResultKeywords&period=day&date=2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getSiteSearchNoResultKeywords&period=day&date=2008-12-06,2009-01-04 + Actions_getSiteSearchNoResultKeywords + + + Actions + Site Search + Page Titles Following a Site Search + Actions + getPageTitlesFollowingSiteSearch + Destination Page + When visitors search on your website, they are looking for a particular page, content, product, or service. This report lists the pages that were clicked the most after an internal search. In other words, the list of pages the most searched for by visitors already on your website.<br/>Use the plus and minus icons on the left to navigate. + + Clicked in search results + Total Pageviews + + + 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. + + + + Pages Following a Site Search + Actions + getPageUrlsFollowingSiteSearch + + + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getPageTitlesFollowingSiteSearch&period=day&date=2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getPageTitlesFollowingSiteSearch&period=day&date=2008-12-06,2009-01-04 + Actions_getPageTitlesFollowingSiteSearch + + + Actions + Site Search + Search Categories + Actions + getSiteSearchCategories + Search Category + This report lists the Categories that visitors selected when they made a Search on your website.<br/>For example, Ecommerce websites typically have a "Category" selector so that visitors can restrict their searches to all products in a specific Category. + + Searches + Search Results pages + % Search Exits + + + The number of visits that searched for this keyword on your website's search engine. + Visitors will search on your website, and sometimes click "next" to view more results. This is the average number of search results pages viewed for this keyword. + The percentage of visits that left the website after searching for this Keyword on your Site Search engine. + + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getSiteSearchCategories&period=day&date=2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getSiteSearchCategories&period=day&date=2008-12-06,2009-01-04 + Actions_getSiteSearchCategories Actions + Outlinks Outlinks Actions getOutlinks @@ -810,6 +1308,7 @@ Actions + Downloads Downloads Actions getDownloads @@ -826,46 +1325,11 @@ getDownloads index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getDownloads&period=day&date=2009-01-04 index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getDownloads&period=day&date=2008-12-06,2009-01-04 - Actions_getDownloads - - - Actions - Content Name - Contents - getContentNames - Content Name - - Impressions - Interactions - - - Interaction Rate - - getContentNames - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Contents&apiAction=getContentNames&period=day&date=2009-01-04 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Contents&apiAction=getContentNames&period=day&date=2008-12-06,2009-01-04 - Contents_getContentNames - - - Actions - Content Piece - Contents - getContentPieces - Content Piece - - Impressions - Interactions - - - Interaction Rate - - getContentPieces - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Contents&apiAction=getContentPieces&period=day&date=2009-01-04 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Contents&apiAction=getContentPieces&period=day&date=2008-12-06,2009-01-04 - Contents_getContentPieces + Actions_getDownloads - Events + Actions + Events Event Categories Events getCategory @@ -894,7 +1358,8 @@ Events_getCategory - Events + Actions + Events Event Actions Events getAction @@ -923,7 +1388,8 @@ Events_getAction - Events + Actions + Events Event Names Events getName @@ -952,110 +1418,154 @@ Events_getName - Site Search - Site Search Keywords - Actions - getSiteSearchKeywords - Keyword - This report lists the Search Keywords that visitors searched for on your internal Search Engine.<br/><br/>Tracking searches that visitors make on your website is a very effective way to learn more about what your audience is looking for, it can help find ideas for new content, new Ecommerce products that potential customers might be searching for, and generally improve the visitors' experience on your website.<br/><br/><a href="http://piwik.org/docs/site-search/" rel="noreferrer" target="_blank">Learn more about Tracking how your visitors use your Search engine.</a> + Actions + Contents + Content Name + Contents + getContentNames + Content Name - Searches - Search Results pages + Impressions + Interactions - - The number of visits that searched for this keyword on your website's search engine. - Visitors will search on your website, and sometimes click "next" to view more results. This is the average number of search results pages viewed for this keyword. - The percentage of visits that left the website after searching for this Keyword on your Site Search engine. - - % Search Exits + Interaction Rate - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getSiteSearchKeywords&period=day&date=2009-01-04 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getSiteSearchKeywords&period=day&date=2008-12-06,2009-01-04 - Actions_getSiteSearchKeywords + getContentNames + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Contents&apiAction=getContentNames&period=day&date=2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Contents&apiAction=getContentNames&period=day&date=2008-12-06,2009-01-04 + Contents_getContentNames - Site Search - Search Keywords with No Results - Actions - getSiteSearchNoResultKeywords - Keyword with No Search Result - Tracking searches that visitors make on your website is a very effective way to learn more about what your audience is looking for, it can help find ideas for new content, new Ecommerce products that potential customers might be searching for, and generally improve the visitors' experience on your website.<br /><br />This report lists the Search Keywords that did not return any Search result: maybe the search engine algorithm can be improved, or maybe your visitors are looking for content that is not (yet) on your website? + Actions + Contents + Content Piece + Contents + getContentPieces + Content Piece - Searches + Impressions + Interactions - - The number of visits that searched for this keyword on your website's search engine. - The percentage of visits that left the website after searching for this Keyword on your Site Search engine. - - % Search Exits + Interaction Rate - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getSiteSearchNoResultKeywords&period=day&date=2009-01-04 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getSiteSearchNoResultKeywords&period=day&date=2008-12-06,2009-01-04 - Actions_getSiteSearchNoResultKeywords + getContentPieces + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Contents&apiAction=getContentPieces&period=day&date=2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Contents&apiAction=getContentPieces&period=day&date=2008-12-06,2009-01-04 + Contents_getContentPieces - Site Search - Search Categories + Actions + Actions - Main metrics Actions - getSiteSearchCategories - Search Category - This report lists the Categories that visitors selected when they made a Search on your website.<br/>For example, Ecommerce websites typically have a "Category" selector so that visitors can restrict their searches to all products in a specific Category. + get - Searches - Search Results pages - % Search Exits + Pageviews + Unique Pageviews + Downloads + Unique Downloads + Outlinks + Unique Outlinks + Searches + Unique Keywords - The number of visits that searched for this keyword on your website's search engine. - Visitors will search on your website, and sometimes click "next" to view more results. This is the average number of search results pages viewed for this keyword. - The percentage of visits that left the website after searching for this Keyword on your Site Search engine. + The number of times this page was visited. + The number of visits that included this page. If a page was viewed multiple times during one visit, it is only counted once. + The number of times this link was clicked. + The number of visits that involved a click on this link. If a link was clicked multiple times during one visit, it is only counted once. + The number of times this link was clicked. + The number of visits that involved a click on this link. If a link was clicked multiple times during one visit, it is only counted once. + The number of visits that searched for this keyword on your website's search engine. + The average time it took to generate the page. This metric includes the time it took the server to generate the web page, plus the time it took for the visitor to download the response from the server. A lower 'Avg. generation time' means a faster website for your visitors! - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getSiteSearchCategories&period=day&date=2009-01-04 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getSiteSearchCategories&period=day&date=2008-12-06,2009-01-04 - Actions_getSiteSearchCategories + + Avg. generation time + + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=get&period=day&date=2008-12-06,2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=get&period=day&date=2008-12-06,2009-01-04 + Actions_get - Site Search - Pages Following a Site Search + Actions + Entry page titles Actions - getPageUrlsFollowingSiteSearch - Destination Page - When visitors search on your website, they are looking for a particular page, content, product, or service. This report lists the pages that were clicked the most after an internal search. In other words, the list of pages the most searched for by visitors already on your website.<br/>Use the plus and minus icons on the left to navigate. + getEntryPageTitles + Entry Page title + This report contains information about the titles of entry pages that were used during the specified period. Use the plus and minus icons on the left to navigate. - Clicked in search results - Total Pageviews + Entrances + Bounces - 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. + Number of visits that started on this page. + Number of visits that started and ended on this page. This means that the visitor left the website after viewing only this page. + Percentage of visits that started and ended on this page. + The average time it took to generate the page. This metric includes the time it took the server to generate the web page, plus the time it took for the visitor to download the response from the server. A lower 'Avg. generation time' means a faster website for your visitors! - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getPageUrlsFollowingSiteSearch&period=day&date=2009-01-04 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getPageUrlsFollowingSiteSearch&period=day&date=2008-12-06,2009-01-04 - Actions_getPageUrlsFollowingSiteSearch + + Bounce Rate + Avg. generation time + + getEntryPageTitles + + + Page titles + Actions + getPageTitles + + + Entry pages + Actions + getEntryPageUrls + + + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getEntryPageTitles&period=day&date=2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getEntryPageTitles&period=day&date=2008-12-06,2009-01-04 + Actions_getEntryPageTitles - Site Search - Page Titles Following a Site Search + Actions + Exit page titles Actions - getPageTitlesFollowingSiteSearch - Destination Page - When visitors search on your website, they are looking for a particular page, content, product, or service. This report lists the pages that were clicked the most after an internal search. In other words, the list of pages the most searched for by visitors already on your website.<br/>Use the plus and minus icons on the left to navigate. + getExitPageTitles + Exit Page Title + This report contains information about the titles of exit pages that occurred during the specified period. Use the plus and minus icons on the left to navigate. - Clicked in search results - Total Pageviews + Exits + Unique Pageviews - 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. + Number of visits that ended on this page. + The number of visits that included this page. If a page was viewed multiple times during one visit, it is only counted once. + The percentage of visits that left the website after viewing this page. + The average time it took to generate the page. This metric includes the time it took the server to generate the web page, plus the time it took for the visitor to download the response from the server. A lower 'Avg. generation time' means a faster website for your visitors! - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getPageTitlesFollowingSiteSearch&period=day&date=2009-01-04 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getPageTitlesFollowingSiteSearch&period=day&date=2008-12-06,2009-01-04 - Actions_getPageTitlesFollowingSiteSearch + + Exit rate + Avg. generation time + + getExitPageTitles + + + Page titles + Actions + getPageTitles + + + Exit pages + Actions + getExitPageUrls + + + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getExitPageTitles&period=day&date=2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Actions&apiAction=getExitPageTitles&period=day&date=2008-12-06,2009-01-04 + Actions_getExitPageTitles Referrers + All Referrers Referrer Type Referrers getReferrerType @@ -1096,6 +1606,7 @@ Referrers + All Referrers All Referrers Referrers getAll @@ -1128,6 +1639,7 @@ Referrers + Search Engines & Keywords Keywords Referrers getKeywords @@ -1168,46 +1680,7 @@ Referrers - Websites - Referrers - getWebsites - Website - In this table, you can see which websites referred visitors to your site. <br /> By clicking on a row in the table, you can see which URLs the links to your website were on. - - Visits - Unique visitors - Actions - Users - - - If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his 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 he visits 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 number of users logged in your website. It is the number of unique active users that have a User ID set (via the Tracking code function 'setUserId'). - 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 - - getUrlsFromWebsiteId - - Conversions - Revenue - - - Revenue per Visit - - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Referrers&apiAction=getWebsites&period=day&date=2009-01-04 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Referrers&apiAction=getWebsites&period=day&date=2008-12-06,2009-01-04 - Referrers_getWebsites - - - Referrers + Search Engines & Keywords Search Engines Referrers getSearchEngines @@ -1248,11 +1721,12 @@ Referrers - Campaigns + Websites & Social + Websites Referrers - getCampaigns - Campaign - This report shows which campaigns led visitors to your website. <br /> For more information about tracking campaigns, read the <a href="http://piwik.org/docs/tracking-campaigns/" rel="noreferrer" target="_blank">campaigns documentation on piwik.org</a> + getWebsites + Website + In this table, you can see which websites referred visitors to your site. <br /> By clicking on a row in the table, you can see which URLs the links to your website were on. Visits Unique visitors @@ -1274,7 +1748,7 @@ Avg. Time on Website Bounce Rate - getKeywordsFromCampaignId + getUrlsFromWebsiteId Conversions Revenue @@ -1282,12 +1756,13 @@ Revenue per Visit - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Referrers&apiAction=getCampaigns&period=day&date=2009-01-04 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Referrers&apiAction=getCampaigns&period=day&date=2008-12-06,2009-01-04 - Referrers_getCampaigns + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Referrers&apiAction=getWebsites&period=day&date=2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Referrers&apiAction=getWebsites&period=day&date=2008-12-06,2009-01-04 + Referrers_getWebsites Referrers + Websites & Social Social Networks Referrers getSocials @@ -1321,55 +1796,35 @@ Referrers_getSocials - Goals - Goals - Goals - get - - Conversions - Visits with Conversions - Revenue - - - The percentage of visits that triggered a goal conversion. - - - Conversion Rate - - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=get&period=day&date=2008-12-06,2009-01-04 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=get&period=day&date=2008-12-06,2009-01-04 - Goals_get - - - Goals - Visits to Conversion - Goals - getVisitsUntilConversion - Visits to Conversion - - Conversions - - 1 - - Conversions - Revenue - - - Revenue per Visit - - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=getVisitsUntilConversion&period=day&date=2009-01-04 - Goals_getVisitsUntilConversion - - - Goals - Days to Conversion - Goals - getDaysToConversion - Days to Conversion + Referrers + Campaigns + Campaigns + Referrers + getCampaigns + Campaign + This report shows which campaigns led visitors to your website. <br /> For more information about tracking campaigns, read the <a href="http://piwik.org/docs/tracking-campaigns/" rel="noreferrer" target="_blank">campaigns documentation on piwik.org</a> - Conversions + Visits + Unique visitors + Actions + Users - 1 + + If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his 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 he visits 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 number of users logged in your website. It is the number of unique active users that have a User ID set (via the Tracking code function 'setUserId'). + 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 + + getKeywordsFromCampaignId Conversions Revenue @@ -1377,274 +1832,223 @@ Revenue per Visit - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=getDaysToConversion&period=day&date=2009-01-04 - Goals_getDaysToConversion + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Referrers&apiAction=getCampaigns&period=day&date=2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Referrers&apiAction=getCampaigns&period=day&date=2008-12-06,2009-01-04 + Referrers_getCampaigns - Goals - Goal Goal 1 - Thank you + Ecommerce + Products + Product SKU Goals - get - - 1 - + getItemsSku + Product SKU - Conversions - Visits with Conversions - Revenue + Product Revenue + Quantity + Unique Purchases + Visits - - The percentage of visits that triggered a goal conversion. - - Conversion Rate + Average Price + Average Quantity + Product Conversion Rate - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=get&idGoal=1&period=day&date=2008-12-06,2009-01-04 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=get&idGoal=1&period=day&date=2008-12-06,2009-01-04 - Goals_get_idGoal--1 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=getItemsSku&period=day&date=2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=getItemsSku&period=day&date=2008-12-06,2009-01-04 + Goals_getItemsSku - Goals - Goal 1 - Thank you - Visits to Conversion + Ecommerce + Products + Product Name Goals - getVisitsUntilConversion - - 1 - - Visits to Conversion + getItemsName + Product Name - Conversions + Product Revenue + Quantity + Unique Purchases + Visits - 1 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=getVisitsUntilConversion&idGoal=1&period=day&date=2009-01-04 - Goals_getVisitsUntilConversion_idGoal--1 + + Average Price + Average Quantity + Product Conversion Rate + + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=getItemsName&period=day&date=2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=getItemsName&period=day&date=2008-12-06,2009-01-04 + Goals_getItemsName - Goals - Goal 1 - Thank you - Days to Conversion + Ecommerce + Products + Product Category Goals - getDaysToConversion - - 1 - - Days to Conversion + getItemsCategory + Product Category - Conversions + Product Revenue + Quantity + Unique Purchases + Visits - 1 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=getDaysToConversion&idGoal=1&period=day&date=2009-01-04 - Goals_getDaysToConversion_idGoal--1 + + Average Price + Average Quantity + Product Conversion Rate + + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=getItemsCategory&period=day&date=2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=getItemsCategory&period=day&date=2008-12-06,2009-01-04 + Goals_getItemsCategory - Goals - Goal Goal 2 - Hello + Ecommerce + Ecommerce Orders Goals get - 2 + ecommerceOrder - Conversions + Ecommerce Orders Visits with Conversions + Conversion Rate Revenue + Subtotal + Tax + Shipping + Discount + Purchased Products The percentage of visits that triggered a goal conversion. - Conversion Rate + Average Order Value - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=get&idGoal=2&period=day&date=2008-12-06,2009-01-04 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=get&idGoal=2&period=day&date=2008-12-06,2009-01-04 - Goals_get_idGoal--2 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=get&idGoal=ecommerceOrder&period=day&date=2008-12-06,2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=get&idGoal=ecommerceOrder&period=day&date=2008-12-06,2009-01-04 + Goals_get_idGoal--ecommerceOrder - Goals - Goal 2 - Hello - Visits to Conversion + Ecommerce + Ecommerce Orders - Visits to Conversion Goals getVisitsUntilConversion - 2 + ecommerceOrder Visits to Conversion Conversions 1 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=getVisitsUntilConversion&idGoal=2&period=day&date=2009-01-04 - Goals_getVisitsUntilConversion_idGoal--2 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=getVisitsUntilConversion&idGoal=ecommerceOrder&period=day&date=2009-01-04 + Goals_getVisitsUntilConversion_idGoal--ecommerceOrder - Goals - Goal 2 - Hello - Days to Conversion + Ecommerce + Ecommerce Orders - Days to Conversion Goals getDaysToConversion - 2 + ecommerceOrder Days to Conversion Conversions 1 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=getDaysToConversion&idGoal=2&period=day&date=2009-01-04 - Goals_getDaysToConversion_idGoal--2 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=getDaysToConversion&idGoal=ecommerceOrder&period=day&date=2009-01-04 + Goals_getDaysToConversion_idGoal--ecommerceOrder - Goals - Goal triggered js + Ecommerce + Abandoned Carts Goals get - 3 - - - Conversions - Visits with Conversions - Revenue - - - The percentage of visits that triggered a goal conversion. - - - Conversion Rate - - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=get&idGoal=3&period=day&date=2008-12-06,2009-01-04 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=get&idGoal=3&period=day&date=2008-12-06,2009-01-04 - Goals_get_idGoal--3 - - - Goals - triggered js - Visits to Conversion - Goals - getVisitsUntilConversion - - 3 - - Visits to Conversion - - Conversions - - 1 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=getVisitsUntilConversion&idGoal=3&period=day&date=2009-01-04 - Goals_getVisitsUntilConversion_idGoal--3 - - - Goals - triggered js - Days to Conversion - Goals - getDaysToConversion - - 3 + ecommerceAbandonedCart - Days to Conversion - - Conversions - - 1 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=getDaysToConversion&idGoal=3&period=day&date=2009-01-04 - Goals_getDaysToConversion_idGoal--3 - - - Visitors - Country - UserCountry - getCountry - Country - This report shows which country your visitors were in when they accessed your website. - - Visits - Unique visitors - Actions - - - If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his 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 he visits 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 - - - Conversions - Revenue - - - Revenue per Visit - - 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 - - - Visitors - Continent - UserCountry - getContinent - Continent - This report shows which continent your visitors were in when they accessed your website. - Visits - Unique visitors - Actions + Abandoned Carts + Conversion Rate + Revenue left in cart + Products left in cart - If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his 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 he visits 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 + Average Order Value - + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=get&idGoal=ecommerceAbandonedCart&period=day&date=2008-12-06,2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=get&idGoal=ecommerceAbandonedCart&period=day&date=2008-12-06,2009-01-04 + Goals_get_idGoal--ecommerceAbandonedCart + + + Ecommerce + Abandoned Carts - Visits to Conversion + Goals + getVisitsUntilConversion + + ecommerceAbandonedCart + + Visits to Conversion + Conversions - Revenue - - - Revenue per Visit - - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=UserCountry&apiAction=getContinent&period=day&date=2009-01-04 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=UserCountry&apiAction=getContinent&period=day&date=2008-12-06,2009-01-04 - UserCountry_getContinent + + 1 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=getVisitsUntilConversion&idGoal=ecommerceAbandonedCart&period=day&date=2009-01-04 + Goals_getVisitsUntilConversion_idGoal--ecommerceAbandonedCart - Visitors - Region - UserCountry - getRegion - Region - This report shows which region your visitors were in when they accessed your website.<br/>In order to see data for this report, you must setup GeoIP in the Geolocation admin tab. The commercial <a rel="noreferrer" target="_blank" href="http://www.maxmind.com/?rId=piwik">Maxmind</a> GeoIP databases are more accurate than the free ones. To see how accurate they are, click <a rel="noreferrer" target="_blank" href="http://www.maxmind.com/en/city_accuracy?rId=piwik">here</a>. + Ecommerce + Abandoned Carts - Days to Conversion + Goals + getDaysToConversion + + ecommerceAbandonedCart + + Days to Conversion - Visits - Unique visitors - Actions + Conversions + + 1 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=getDaysToConversion&idGoal=ecommerceAbandonedCart&period=day&date=2009-01-04 + Goals_getDaysToConversion_idGoal--ecommerceAbandonedCart + + + Goals + Goals + Goals + get + + Conversions + Visits with Conversions + Revenue - If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his 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 he visits 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 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=get&period=day&date=2008-12-06,2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=get&period=day&date=2008-12-06,2009-01-04 + Goals_get + + + Goals + Visits to Conversion + Goals + getVisitsUntilConversion + Visits to Conversion + + Conversions + + 1 Conversions Revenue @@ -1652,36 +2056,19 @@ Revenue per Visit - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=UserCountry&apiAction=getRegion&period=day&date=2009-01-04 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=UserCountry&apiAction=getRegion&period=day&date=2008-12-06,2009-01-04 - UserCountry_getRegion + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=getVisitsUntilConversion&period=day&date=2009-01-04 + Goals_getVisitsUntilConversion - Visitors - City - UserCountry - getCity - City - This report shows the cities your visitors were in when they accessed your website.<br/>In order to see data for this report, you must setup GeoIP in the Geolocation admin tab. The commercial <a rel="noreferrer" target="_blank" href="http://www.maxmind.com/?rId=piwik">Maxmind</a> GeoIP databases are more accurate than the free ones. To see how accurate they are, click <a rel="noreferrer" target="_blank" href="http://www.maxmind.com/en/city_accuracy?rId=piwik">here</a>. + Goals + Days to Conversion + Goals + getDaysToConversion + Days to Conversion - Visits - Unique visitors - Actions + Conversions - - If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his 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 he visits 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 - + 1 Conversions Revenue @@ -1689,245 +2076,180 @@ Revenue per Visit - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=UserCountry&apiAction=getCity&period=day&date=2009-01-04 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=UserCountry&apiAction=getCity&period=day&date=2008-12-06,2009-01-04 - UserCountry_getCity + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=getDaysToConversion&period=day&date=2009-01-04 + Goals_getDaysToConversion - Visitors - Custom Variables - CustomVariables - getCustomVariables - Custom Variable name - This report contains information about your Custom Variables. Click on a variable name to see the distribution of the values. <br /> For more information about Custom Variables in general, read the <a href="http://piwik.org/docs/custom-variables/" rel="noreferrer" target="_blank">Custom Variables documentation on piwik.org</a> + Goals + Goal Goal 1 - Thank you + Goals + get + + 1 + - Visits - Unique visitors - Actions - Users + Conversions + Visits with Conversions + Revenue - If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his 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 he visits 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 number of users logged in your website. It is the number of unique active users that have a User ID set (via the Tracking code function 'setUserId'). - 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 - getCustomVariablesValuesFromNameId - - Conversions - Revenue - - - Revenue per Visit - - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=CustomVariables&apiAction=getCustomVariables&period=day&date=2009-01-04 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=CustomVariables&apiAction=getCustomVariables&period=day&date=2008-12-06,2009-01-04 - CustomVariables_getCustomVariables + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=get&idGoal=1&period=day&date=2008-12-06,2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=get&idGoal=1&period=day&date=2008-12-06,2009-01-04 + Goals_get_idGoal--1 - Visitors - Length of Visits - VisitorInterest - getNumberOfVisitsPerVisitDuration - Visit duration - In this report, you can see how many visits had a certain total duration. Initially, the report is shown as a tag cloud, more common durations are displayed in a larger font.<br />Please note, that you can view the report in other ways than as a tag cloud. Use the controls at the bottom of the report to do so. + Goals + Goal 1 - Thank you - Visits to Conversion + Goals + getVisitsUntilConversion + + 1 + + Visits to Conversion - Visits + Conversions - - If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit. - 1 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=VisitorInterest&apiAction=getNumberOfVisitsPerVisitDuration&period=day&date=2009-01-04 - VisitorInterest_getNumberOfVisitsPerVisitDuration + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=getVisitsUntilConversion&idGoal=1&period=day&date=2009-01-04 + Goals_getVisitsUntilConversion_idGoal--1 - Visitors - Pages per Visit - VisitorInterest - getNumberOfVisitsPerPage - Pages per visit - In this report, you can see how many visits involved a certain number of pageviews. Initially, the report is shown as a tag cloud, more common numbers of pages are displayed in a larger font.<br />Please note, that you can view the report in other ways than as a tag cloud. Use the controls at the bottom of the report to do so. + Goals + Goal 1 - Thank you - Days to Conversion + Goals + getDaysToConversion + + 1 + + Days to Conversion - Visits + Conversions - - If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit. - 1 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=VisitorInterest&apiAction=getNumberOfVisitsPerPage&period=day&date=2009-01-04 - VisitorInterest_getNumberOfVisitsPerPage + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=getDaysToConversion&idGoal=1&period=day&date=2009-01-04 + Goals_getDaysToConversion_idGoal--1 - Visitors - Visits by Visit Number - VisitorInterest - getNumberOfVisitsByVisitCount - Visits by Visit Number - In this report, you can see the number of visits who were the Nth visit, ie. visitors who visited your website at least N times.<br />Please note, that you can view the report in other ways than as a tag cloud. Use the controls at the bottom of the report to do so. + Goals + Goal Goal 2 - Hello + Goals + get + + 2 + - Visits + Conversions + Visits with Conversions + Revenue - If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit. + The percentage of visits that triggered a goal conversion. - % Visits + Conversion Rate - 1 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=VisitorInterest&apiAction=getNumberOfVisitsByVisitCount&period=day&date=2009-01-04 - VisitorInterest_getNumberOfVisitsByVisitCount + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=get&idGoal=2&period=day&date=2008-12-06,2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=get&idGoal=2&period=day&date=2008-12-06,2009-01-04 + Goals_get_idGoal--2 - Visitors - Visits by days since last visit - VisitorInterest - getNumberOfVisitsByDaysSinceLast - Visits by days since last visit - In this report, you can see how many visits were from visitors whose last visit was a certain number of days ago. + Goals + Goal 2 - Hello - Visits to Conversion + Goals + getVisitsUntilConversion + + 2 + + Visits to Conversion - Visits + Conversions - - If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit. - 1 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=VisitorInterest&apiAction=getNumberOfVisitsByDaysSinceLast&period=day&date=2009-01-04 - VisitorInterest_getNumberOfVisitsByDaysSinceLast + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=getVisitsUntilConversion&idGoal=2&period=day&date=2009-01-04 + Goals_getVisitsUntilConversion_idGoal--2 - Visitors - Returning Visits - VisitFrequency - get + Goals + Goal 2 - Hello - Days to Conversion + Goals + getDaysToConversion + + 2 + + Days to Conversion - Returning Visits - Actions by Returning Visits - Unique returning visitors - Returning Users - Maximum actions in one returning visit + Conversions - - Avg. Duration of a Returning Visit (in sec) - Avg. Actions per Returning Visit - Bounce Rate for Returning Visits - - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=VisitFrequency&apiAction=get&period=day&date=2008-12-06,2009-01-04 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=VisitFrequency&apiAction=get&period=day&date=2008-12-06,2009-01-04 - VisitFrequency_get + 1 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=getDaysToConversion&idGoal=2&period=day&date=2009-01-04 + Goals_getDaysToConversion_idGoal--2 - Visitor Devices - Device type - DevicesDetection - getType - Device type + Goals + Goal triggered js + Goals + get + + 3 + - Visits - Unique visitors - Actions - Users + Conversions + Visits with Conversions + Revenue - If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his 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 he visits 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 number of users logged in your website. It is the number of unique active users that have a User ID set (via the Tracking code function 'setUserId'). - 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 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=DevicesDetection&apiAction=getType&period=day&date=2009-01-04 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=DevicesDetection&apiAction=getType&period=day&date=2008-12-06,2009-01-04 - DevicesDetection_getType + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=get&idGoal=3&period=day&date=2008-12-06,2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=get&idGoal=3&period=day&date=2008-12-06,2009-01-04 + Goals_get_idGoal--3 - Visitor Devices - Visitor Browser - DevicesDetection - getBrowsers - Browser - This report contains information about what kind of browser your visitors were using. Each browser version is listed separately. + Goals + triggered js - Visits to Conversion + Goals + getVisitsUntilConversion + + 3 + + Visits to Conversion - Visits - Unique visitors - Actions - Users + Conversions - - If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his 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 he visits 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 number of users logged in your website. It is the number of unique active users that have a User ID set (via the Tracking code function 'setUserId'). - 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 - - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=DevicesDetection&apiAction=getBrowsers&period=day&date=2009-01-04 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=DevicesDetection&apiAction=getBrowsers&period=day&date=2008-12-06,2009-01-04 - DevicesDetection_getBrowsers + 1 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=getVisitsUntilConversion&idGoal=3&period=day&date=2009-01-04 + Goals_getVisitsUntilConversion_idGoal--3 - Visitor Devices - Device brand - DevicesDetection - getBrand - Device brand + Goals + triggered js - Days to Conversion + Goals + getDaysToConversion + + 3 + + Days to Conversion - Visits - Unique visitors - Actions - Users + Conversions - - If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his 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 he visits 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 number of users logged in your website. It is the number of unique active users that have a User ID set (via the Tracking code function 'setUserId'). - 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 - - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=DevicesDetection&apiAction=getBrand&period=day&date=2009-01-04 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=DevicesDetection&apiAction=getBrand&period=day&date=2008-12-06,2009-01-04 - DevicesDetection_getBrand + 1 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=Goals&apiAction=getDaysToConversion&idGoal=3&period=day&date=2009-01-04 + Goals_getDaysToConversion_idGoal--3 - Visitor Devices - Browser version - DevicesDetection - getBrowserVersions - Browser version + UI Framework + Data tables + Data tables + ExampleUI + getTemperatures Visits Unique visitors @@ -1950,16 +2272,15 @@ Bounce Rate Conversion Rate - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=DevicesDetection&apiAction=getBrowserVersions&period=day&date=2009-01-04 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=DevicesDetection&apiAction=getBrowserVersions&period=day&date=2008-12-06,2009-01-04 - DevicesDetection_getBrowserVersions + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=ExampleUI&apiAction=getTemperatures&period=day&date=2008-12-06,2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=ExampleUI&apiAction=getTemperatures&period=day&date=2008-12-06,2009-01-04 + ExampleUI_getTemperatures - Visitor Devices - Device model - DevicesDetection - getModel - Device model + UI Framework + Temperatures evolution over time + ExampleUI + getTemperaturesEvolution Visits Unique visitors @@ -1982,16 +2303,16 @@ Bounce Rate Conversion Rate - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=DevicesDetection&apiAction=getModel&period=day&date=2009-01-04 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=DevicesDetection&apiAction=getModel&period=day&date=2008-12-06,2009-01-04 - DevicesDetection_getModel + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=ExampleUI&apiAction=getTemperaturesEvolution&period=day&date=2008-12-06,2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=ExampleUI&apiAction=getTemperaturesEvolution&period=day&date=2008-12-06,2009-01-04 + ExampleUI_getTemperaturesEvolution - Visitor Devices - Operating System families - DevicesDetection - getOsFamilies - Operating system family + UI Framework + Pie graph + Pie graph + ExampleUI + getPlanetRatios Visits Unique visitors @@ -2014,16 +2335,16 @@ Bounce Rate Conversion Rate - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=DevicesDetection&apiAction=getOsFamilies&period=day&date=2009-01-04 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=DevicesDetection&apiAction=getOsFamilies&period=day&date=2008-12-06,2009-01-04 - DevicesDetection_getOsFamilies + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=ExampleUI&apiAction=getPlanetRatios&period=day&date=2008-12-06,2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=ExampleUI&apiAction=getPlanetRatios&period=day&date=2008-12-06,2009-01-04 + ExampleUI_getPlanetRatios - Visitor Devices - Operating System versions - DevicesDetection - getOsVersions - Operating System versions + UI Framework + Tag clouds + Advanced tag cloud: with logos and links + ExampleUI + getPlanetRatiosWithLogos Visits Unique visitors @@ -2046,41 +2367,68 @@ Bounce Rate Conversion Rate - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=DevicesDetection&apiAction=getOsVersions&period=day&date=2009-01-04 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=DevicesDetection&apiAction=getOsVersions&period=day&date=2008-12-06,2009-01-04 - DevicesDetection_getOsVersions + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=ExampleUI&apiAction=getPlanetRatiosWithLogos&period=day&date=2008-12-06,2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=ExampleUI&apiAction=getPlanetRatiosWithLogos&period=day&date=2008-12-06,2009-01-04 + ExampleUI_getPlanetRatiosWithLogos - Visitor Devices - Browser engines - DevicesDetection - getBrowserEngines - Browser engine - This report shows your visitors' browsers broken down into browser engines. <br /> The most important information for web developers is what kind of rendering engine their visitors are using. The labels contain the names of the engines followed by the most common browser using that engine in brackets. + API + Main metrics + API + get - Visits + Pageviews + Unique Pageviews + Downloads + Unique Downloads + Outlinks + Unique Outlinks + Searches + Unique Keywords + Conversions + Visits with Conversions + Revenue Unique visitors - Actions + Visits Users + Actions + Maximum actions in one visit + Returning Visits + Actions by Returning Visits + Unique returning visitors + Returning Users + Maximum actions in one returning visit - If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit. + The number of times this page was visited. + The number of visits that included this page. If a page was viewed multiple times during one visit, it is only counted once. + The number of times this link was clicked. + The number of visits that involved a click on this link. If a link was clicked multiple times during one visit, it is only counted once. + The number of times this link was clicked. + The number of visits that involved a click on this link. If a link was clicked multiple times during one visit, it is only counted once. + The number of visits that searched for this keyword on your website's search engine. The number of unduplicated visitors coming to your website. Every user is only counted once, even if he visits 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. + If a visitor comes to your website for the first time or if he visits a page more than 30 minutes after his last page view, this will be recorded as a new visit. The number of users logged in your website. It is the number of unique active users that have a User ID set (via the Tracking code function 'setUserId'). + The number of actions performed by your visitors. Actions can be page views, internal site searches, downloads or outlinks. + The average time it took to generate the page. This metric includes the time it took the server to generate the web page, plus the time it took for the visitor to download the response from the server. A lower 'Avg. generation time' means a faster website for your visitors! + The percentage of visits that triggered a goal conversion. + The percentage of visits that only had a single pageview. This means, that the visitor left the website directly from the entrance page. 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 + Avg. generation time Conversion Rate + Bounce Rate + Actions per Visit + Avg. Visit Duration (in seconds) + Avg. Duration of a Returning Visit (in sec) + Avg. Actions per Returning Visit + Bounce Rate for Returning Visits - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=DevicesDetection&apiAction=getBrowserEngines&period=day&date=2009-01-04 - index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=DevicesDetection&apiAction=getBrowserEngines&period=day&date=2008-12-06,2009-01-04 - DevicesDetection_getBrowserEngines + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=API&apiAction=get&period=day&date=2008-12-06,2009-01-04 + index.php?module=API&method=ImageGraph.get&idSite=1&apiModule=API&apiAction=get&period=day&date=2008-12-06,2009-01-04 + API_get \ No newline at end of file diff --git a/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getReportPagesMetadata.xml b/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getReportPagesMetadata.xml new file mode 100644 index 0000000000..efd59d9e85 --- /dev/null +++ b/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getReportPagesMetadata.xml @@ -0,0 +1,4074 @@ + + + + General_Actions.General_Downloads + + General_Actions + Actions + 10 + + + General_Downloads + Downloads + 35 + + + + Downloads + Actions + getDownloads + 109 + + Actions + getDownloads + + widgetActionsgetDownloads + table + 1 + + + + + General_Actions.Actions_SubmenuPagesEntry + + General_Actions + Actions + 10 + + + Actions_SubmenuPagesEntry + Entry pages + 10 + + + + Entry pages + Actions + getEntryPageUrls + 103 + + Actions + getEntryPageUrls + + widgetActionsgetEntryPageUrls + table + 1 + + + + + General_Actions.Actions_SubmenuPagesExit + + General_Actions + Actions + 10 + + + Actions_SubmenuPagesExit + Exit pages + 15 + + + + Exit pages + Actions + getExitPageUrls + 104 + + Actions + getExitPageUrls + + widgetActionsgetExitPageUrls + table + 1 + + + + + General_Actions.General_Outlinks + + General_Actions + Actions + 10 + + + General_Outlinks + Outlinks + 30 + + + + Outlinks + Actions + getOutlinks + 108 + + Actions + getOutlinks + + widgetActionsgetOutlinks + table + 1 + + + + + General_Actions.General_Pages + + General_Actions + Actions + 10 + + + General_Pages + Pages + 5 + + + + Pages + Actions + getPageUrls + 102 + + Actions + getPageUrls + + widgetActionsgetPageUrls + table + 1 + + + + + General_Actions.Actions_SubmenuPageTitles + + General_Actions + Actions + 10 + + + Actions_SubmenuPageTitles + Page titles + 20 + + + + Page titles + Actions + getPageTitles + 105 + + Actions + getPageTitles + + widgetActionsgetPageTitles + table + 1 + + + + + General_Actions.Actions_SubmenuSitesearch + + General_Actions + Actions + 10 + + + Actions_SubmenuSitesearch + Site Search + 25 + + + + Site Search Keywords + Actions + getSiteSearchKeywords + 115 + + Actions + getSiteSearchKeywords + + widgetActionsgetSiteSearchKeywords + table + 1 + + + Pages Following a Site Search + Actions + getPageUrlsFollowingSiteSearch + 116 + + Actions + getPageUrlsFollowingSiteSearch + + widgetActionsgetPageUrlsFollowingSiteSearch + table + 1 + + + Search Keywords with No Results + Actions + getSiteSearchNoResultKeywords + 118 + + Actions + getSiteSearchNoResultKeywords + + widgetActionsgetSiteSearchNoResultKeywords + table + 1 + + + Page Titles Following a Site Search + Actions + getPageTitlesFollowingSiteSearch + 119 + + Actions + getPageTitlesFollowingSiteSearch + + widgetActionsgetPageTitlesFollowingSiteSearch + table + 1 + + + Search Categories + Actions + getSiteSearchCategories + 120 + + Actions + getSiteSearchCategories + + widgetActionsgetSiteSearchCategories + table + 1 + + + + + General_Actions.Events_Events + + General_Actions + Actions + 10 + + + Events_Events + Events + 40 + + + + + CoreHome + renderWidgetContainer + 99 + + CoreHome + renderWidgetContainer + Events + + widgetEvents + ByDimension + 1 + + + Event Categories + + General_Actions + Actions + 99 + + + Events_Events + Events + 99 + + Events + getCategory + 100 + + Events + getCategory + eventAction + + widgetEventsgetCategorysecondaryDimensioneventAction + table + 1 + + + Event Actions + + General_Actions + Actions + 99 + + + Events_Events + Events + 99 + + Events + getAction + 101 + + Events + getAction + eventName + + widgetEventsgetActionsecondaryDimensioneventName + table + 1 + + + Event Names + + General_Actions + Actions + 99 + + + Events_Events + Events + 99 + + Events + getName + 102 + + Events + getName + eventAction + + widgetEventsgetNamesecondaryDimensioneventAction + table + 1 + + + + + + + General_Actions.Contents_Contents + + General_Actions + Actions + 10 + + + Contents_Contents + Contents + 45 + + + + + CoreHome + renderWidgetContainer + 99 + + CoreHome + renderWidgetContainer + Contents + + widgetContents + ByDimension + 1 + + + Content Name + + General_Actions + Actions + 99 + + + Contents_Contents + Contents + 99 + + Contents + getContentNames + 135 + + Contents + getContentNames + + widgetContentsgetContentNames + table + 1 + + + Content Piece + + General_Actions + Actions + 99 + + + Contents_Contents + Contents + 99 + + Contents + getContentPieces + 136 + + Contents + getContentPieces + + widgetContentsgetContentPieces + table + 1 + + + + + + + General_Visitors.DevicesDetection_Devices + + General_Visitors + Visitors + 5 + + + DevicesDetection_Devices + Devices + 15 + + + + Device type + DevicesDetection + getType + 100 + + DevicesDetection + getType + + widgetDevicesDetectiongetType + table + 1 + + + Device model + DevicesDetection + getModel + 102 + + DevicesDetection + getModel + + widgetDevicesDetectiongetModel + table + 1 + + + Device brand + DevicesDetection + getBrand + 104 + + DevicesDetection + getBrand + + widgetDevicesDetectiongetBrand + table + 1 + + + Screen Resolution + Resolution + getResolution + 108 + + Resolution + getResolution + + widgetResolutiongetResolution + table + 1 + + + + + General_Visitors.VisitorInterest_Engagement + + General_Visitors + Visitors + 5 + + + VisitorInterest_Engagement + Engagement + 30 + + + + Visits per visit duration + VisitorInterest + getNumberOfVisitsPerVisitDuration + 115 + + cloud + VisitorInterest + getNumberOfVisitsPerVisitDuration + + widgetVisitorInterestgetNumberOfVisitsPerVisitDurationviewDataTablecloud + cloud + 1 + + + Visits per number of pages + VisitorInterest + getNumberOfVisitsPerPage + 120 + + cloud + VisitorInterest + getNumberOfVisitsPerPage + + widgetVisitorInterestgetNumberOfVisitsPerPageviewDataTablecloud + cloud + 1 + + + Visits by Visit Number + VisitorInterest + getNumberOfVisitsByVisitCount + 125 + + VisitorInterest + getNumberOfVisitsByVisitCount + + widgetVisitorInterestgetNumberOfVisitsByVisitCount + table + 1 + + + Visits by Days Since Last Visit + VisitorInterest + getNumberOfVisitsByDaysSinceLast + 130 + + VisitorInterest + getNumberOfVisitsByDaysSinceLast + + widgetVisitorInterestgetNumberOfVisitsByDaysSinceLast + table + 1 + + + Returning Visits Over Time + VisitFrequency + getEvolutionGraph + 1 + + 1 + graphEvolution + VisitFrequency + getEvolutionGraph + + widgetVisitFrequencygetEvolutionGraphforceView1viewDataTablegraphEvolution + graphEvolution + 1 + + + Frequency Overview + VisitFrequency + get + 2 + + 1 + sparklines + VisitFrequency + get + + widgetVisitFrequencygetforceView1viewDataTablesparklines + sparklines + 1 + + + + + General_Visitors.DevicesDetection_Software + + General_Visitors + Visitors + 5 + + + DevicesDetection_Software + Software + 20 + + + + Operating System versions + DevicesDetection + getOsVersions + 102 + + DevicesDetection + getOsVersions + + widgetDevicesDetectiongetOsVersions + table + 1 + + + Browsers + DevicesDetection + getBrowsers + 105 + + DevicesDetection + getBrowsers + + widgetDevicesDetectiongetBrowsers + table + 1 + + + Browser version + DevicesDetection + getBrowserVersions + 106 + + DevicesDetection + getBrowserVersions + + widgetDevicesDetectiongetBrowserVersions + table + 1 + + + Configurations + Resolution + getConfiguration + 107 + + Resolution + getConfiguration + + widgetResolutiongetConfiguration + table + 1 + + + Operating System families + DevicesDetection + getOsFamilies + 108 + + DevicesDetection + getOsFamilies + + widgetDevicesDetectiongetOsFamilies + table + 1 + + + Browser engines + DevicesDetection + getBrowserEngines + 110 + + graphPie + DevicesDetection + getBrowserEngines + + widgetDevicesDetectiongetBrowserEnginesviewDataTablegraphPie + graphPie + 1 + + + Browser Plugins + DevicePlugins + getPlugin + 113 + + DevicePlugins + getPlugin + + widgetDevicePluginsgetPlugin + table + 1 + + + + + General_Visitors.General_Overview + + General_Visitors + Visitors + 5 + + + General_Overview + Overview + 2 + + + + Visits Over Time + VisitsSummary + getEvolutionGraph + 5 + + 1 + graphEvolution + VisitsSummary + getEvolutionGraph + + widgetVisitsSummarygetEvolutionGraphforceView1viewDataTablegraphEvolution + graphEvolution + 1 + + + Visits Overview + VisitsSummary + get + 10 + + 1 + sparklines + VisitsSummary + get + + widgetVisitsSummarygetforceView1viewDataTablesparklines + sparklines + 1 + + + + + General_Visitors.UserCountry_SubmenuLocations + + General_Visitors + Visitors + 5 + + + UserCountry_SubmenuLocations + Locations + 25 + + + + Visitor Map + UserCountryMap + visitorMap + 1 + + UserCountryMap + visitorMap + + widgetUserCountryMapvisitorMap + + + Country + UserCountry + getCountry + 105 + + UserCountry + getCountry + + widgetUserCountrygetCountry + table + 1 + + + + CoreHome + renderWidgetContainer + 106 + + CoreHome + renderWidgetContainer + Continent + + widgetContinent + + 1 + + + Continent + + General_Visitors + Visitors + 99 + + + UserCountry_SubmenuLocations + Locations + 99 + + UserCountry + getContinent + 106 + + UserCountry + getContinent + + widgetUserCountrygetContinent + table + 1 + + + + + General_Visitors + Visitors + 99 + + + UserCountry_SubmenuLocations + Locations + 99 + + UserCountry + getDistinctCountries + 106 + + UserCountry + getDistinctCountries + + widgetUserCountrygetDistinctCountries + table + 1 + + + + + Region + UserCountry + getRegion + 107 + + UserCountry + getRegion + + widgetUserCountrygetRegion + table + 1 + + + Browser language + UserLanguage + getLanguage + 108 + + UserLanguage + getLanguage + + widgetUserLanguagegetLanguage + table + 1 + + + City + UserCountry + getCity + 110 + + UserCountry + getCity + + widgetUserCountrygetCity + table + 1 + + + Language code + UserLanguage + getLanguageCode + 111 + + UserLanguage + getLanguageCode + + widgetUserLanguagegetLanguageCode + table + 1 + + + Providers + Provider + getProvider + 150 + + Provider + getProvider + + widgetProvidergetProvider + table + 1 + + + + + General_Visitors.VisitTime_SubmenuTimes + + General_Visitors + Visitors + 5 + + + VisitTime_SubmenuTimes + Times + 35 + + + + Visits per local time + VisitTime + getVisitInformationPerLocalTime + 115 + + graphVerticalBar + VisitTime + getVisitInformationPerLocalTime + + widgetVisitTimegetVisitInformationPerLocalTimeviewDataTablegraphVerticalBar + graphVerticalBar + 1 + + + Visits per server time + VisitTime + getVisitInformationPerServerTime + 120 + + graphVerticalBar + VisitTime + getVisitInformationPerServerTime + + widgetVisitTimegetVisitInformationPerServerTimeviewDataTablegraphVerticalBar + graphVerticalBar + 1 + + + Visits by Day of Week + VisitTime + getByDayOfWeek + 125 + + graphVerticalBar + VisitTime + getByDayOfWeek + + widgetVisitTimegetByDayOfWeekviewDataTablegraphVerticalBar + graphVerticalBar + 1 + + + + + General_Visitors.UserCountryMap_RealTimeMap + + General_Visitors + Visitors + 5 + + + UserCountryMap_RealTimeMap + Real-time Map + 40 + + + + Real-time Map + UserCountryMap + realtimeMap + 5 + + UserCountryMap + realtimeMap + + widgetUserCountryMaprealtimeMap + + + + + General_Visitors.Live_VisitorLog + + General_Visitors + Visitors + 5 + + + Live_VisitorLog + Visitor Log + 5 + + + + Visitor Log + Live + getLastVisitsDetails + 10 + + 1 + Piwik\Plugins\Live\VisitorLog + Live + getLastVisitsDetails + 1 + + widgetLivegetLastVisitsDetailsforceView1viewDataTablePiwik%5CPlugins%5CLive%5CVisitorLogsmall1 + Piwik\Plugins\Live\VisitorLog + 1 + + + + + General_Visitors.CustomVariables_CustomVariables + + General_Visitors + Visitors + 5 + + + CustomVariables_CustomVariables + Custom Variables + 10 + + + + Custom Variables + CustomVariables + getCustomVariables + 110 + + CustomVariables + getCustomVariables + + widgetCustomVariablesgetCustomVariables + table + 1 + + + + + Dashboard_Dashboard.1 + + Dashboard_Dashboard + Dashboard + 0 + + + 1 + Dashboard + 0 + + + + + Dashboard + embeddedIndex + 99 + + Dashboard + embeddedIndex + 1 + + widgetDashboardembeddedIndexidDashboard1 + + + + + Referrers_Referrers.Referrers_WidgetGetAll + + Referrers_Referrers + Referrers + 15 + + + Referrers_WidgetGetAll + All Referrers + 5 + + + + Referrer Types + Referrers + getReferrerType + 101 + + tableAllColumns + Referrers + getReferrerType + + widgetReferrersgetReferrerTypeviewDataTabletableAllColumns + tableAllColumns + 1 + + + Referrers + Referrers + getAll + 102 + + tableAllColumns + Referrers + getAll + + widgetReferrersgetAllviewDataTabletableAllColumns + tableAllColumns + 1 + + + + + Referrers_Referrers.Referrers_Campaigns + + Referrers_Referrers + Referrers + 15 + + + Referrers_Campaigns + Campaigns + 20 + + + + Campaigns + Referrers + getCampaigns + 109 + + Referrers + getCampaigns + + widgetReferrersgetCampaigns + table + 1 + + + + + Referrers_Referrers.General_Overview + + Referrers_Referrers + Referrers + 15 + + + General_Overview + Overview + 2 + + + + Evolution over the period + Referrers + getEvolutionGraph + 101 + + 1 + graphEvolution + Referrers + getEvolutionGraph + + nb_visits + + + widgetReferrersgetEvolutionGraphforceView1viewDataTablegraphEvolutioncolumnsArray + graphEvolution + 1 + + + Referrer Type + Referrers + getSparklines + 10 + + 1 + sparklines + Referrers + getSparklines + + widgetReferrersgetSparklinesforceView1viewDataTablesparklines + sparklines + 1 + + + + + Referrers_Referrers.Referrers_SubmenuSearchEngines + + Referrers_Referrers + Referrers + 15 + + + Referrers_SubmenuSearchEngines + Search Engines & Keywords + 10 + + + + Keywords + Referrers + getKeywords + 103 + + Referrers + getKeywords + + widgetReferrersgetKeywords + table + 1 + + + Search Engines + Referrers + getSearchEngines + 107 + + Referrers + getSearchEngines + + widgetReferrersgetSearchEngines + table + 1 + + + + + Referrers_Referrers.Referrers_SubmenuWebsites + + Referrers_Referrers + Referrers + 15 + + + Referrers_SubmenuWebsites + Websites & Social + 15 + + + + Websites + Referrers + getWebsites + 105 + + Referrers + getWebsites + + widgetReferrersgetWebsites + table + 1 + + + Social Networks + Referrers + getSocials + 111 + + graphPie + Referrers + getSocials + + widgetReferrersgetSocialsviewDataTablegraphPie + graphPie + 1 + + + + + Goals_Goals.1 + + Goals_Goals + Goals + 25 + + + 1 + Goal 1 - Thank you + 900 + + + + Goal 1 - Thank you + CoreHome + renderWidgetContainer + 15 + + CoreHome + renderWidgetContainer + Goal_1 + + widgetGoal_1 + + 1 + + + + + Goals_Goals + Goals + 99 + + + 1 + 1 + 99 + + Goals + getEvolutionGraph + 13 + + 1 + graphEvolution + Goals + getEvolutionGraph + 1 + + widgetGoalsgetEvolutionGraphforceView1viewDataTablegraphEvolutionidGoal1 + graphEvolution + 1 + + + + + Goals_Goals + Goals + 99 + + + 1 + 1 + 99 + + Goals + get + 14 + + 1 + sparklines + Goals + get + 1 + 1 + + widgetGoalsgetforceView1viewDataTablesparklinesidGoal1allow_multiple1 + sparklines + 1 + + + Conversions Overview + + Goals_Goals + Goals + 99 + + + 1 + 1 + 99 + + Goals + goalConversionsOverview + 15 + + Goals + goalConversionsOverview + 1 + + widgetGoalsgoalConversionsOverviewidGoal1 + + Goals + hasConversions + 1 + + table + 1 + + + + + Goal Goal 1 - Thank you conversions by type of visit + CoreHome + renderWidgetContainer + 17 + + CoreHome + renderWidgetContainer + Goals1 + + widgetGoals1 + + Goals + hasConversions + 1 + + ByDimension + 1 + + + Custom Variables + + Goals by User attribute + Goals by User attribute + 99 + + + Goals by User attribute + Goals by User attribute + 99 + + CustomVariables + getCustomVariables + 301 + + tableGoals + CustomVariables + getCustomVariables + 1 + 1 + + widgetCustomVariablesgetCustomVariablesviewDataTabletableGoalsdocumentationForGoalsPage1idGoal1 + tableGoals + 1 + + + Visits per server time + + Goals by User attribute + Goals by User attribute + 99 + + + Goals by User attribute + Goals by User attribute + 99 + + VisitTime + getVisitInformationPerServerTime + 302 + + tableGoals + VisitTime + getVisitInformationPerServerTime + 1 + 1 + + widgetVisitTimegetVisitInformationPerServerTimeviewDataTabletableGoalsdocumentationForGoalsPage1idGoal1 + tableGoals + 1 + + + Country + + Goals by User location + Goals by User location + 99 + + + Goals by User location + Goals by User location + 99 + + UserCountry + getCountry + 201 + + tableGoals + UserCountry + getCountry + 1 + 1 + + widgetUserCountrygetCountryviewDataTabletableGoalsdocumentationForGoalsPage1idGoal1 + tableGoals + 1 + + + Continent + + Goals by User location + Goals by User location + 99 + + + Goals by User location + Goals by User location + 99 + + UserCountry + getContinent + 202 + + tableGoals + UserCountry + getContinent + 1 + 1 + + widgetUserCountrygetContinentviewDataTabletableGoalsdocumentationForGoalsPage1idGoal1 + tableGoals + 1 + + + Region + + Goals by User location + Goals by User location + 99 + + + Goals by User location + Goals by User location + 99 + + UserCountry + getRegion + 203 + + tableGoals + UserCountry + getRegion + 1 + 1 + + widgetUserCountrygetRegionviewDataTabletableGoalsdocumentationForGoalsPage1idGoal1 + tableGoals + 1 + + + City + + Goals by User location + Goals by User location + 99 + + + Goals by User location + Goals by User location + 99 + + UserCountry + getCity + 204 + + tableGoals + UserCountry + getCity + 1 + 1 + + widgetUserCountrygetCityviewDataTabletableGoalsdocumentationForGoalsPage1idGoal1 + tableGoals + 1 + + + Referrer Type + + Goals by Referrers + Goals by Referrers + 99 + + + Goals by Referrers + Goals by Referrers + 99 + + Referrers + getReferrerType + 1 + + tableGoals + Referrers + getReferrerType + 1 + 1 + + widgetReferrersgetReferrerTypeviewDataTabletableGoalsdocumentationForGoalsPage1idGoal1 + tableGoals + 1 + + + Keywords + + Goals by Referrers + Goals by Referrers + 99 + + + Goals by Referrers + Goals by Referrers + 99 + + Referrers + getKeywords + 2 + + tableGoals + Referrers + getKeywords + 1 + 1 + + widgetReferrersgetKeywordsviewDataTabletableGoalsdocumentationForGoalsPage1idGoal1 + tableGoals + 1 + + + Search Engines + + Goals by Referrers + Goals by Referrers + 99 + + + Goals by Referrers + Goals by Referrers + 99 + + Referrers + getSearchEngines + 3 + + tableGoals + Referrers + getSearchEngines + 1 + 1 + + widgetReferrersgetSearchEnginesviewDataTabletableGoalsdocumentationForGoalsPage1idGoal1 + tableGoals + 1 + + + Websites + + Goals by Referrers + Goals by Referrers + 99 + + + Goals by Referrers + Goals by Referrers + 99 + + Referrers + getWebsites + 4 + + tableGoals + Referrers + getWebsites + 1 + 1 + + widgetReferrersgetWebsitesviewDataTabletableGoalsdocumentationForGoalsPage1idGoal1 + tableGoals + 1 + + + Campaigns + + Goals by Referrers + Goals by Referrers + 99 + + + Goals by Referrers + Goals by Referrers + 99 + + Referrers + getCampaigns + 5 + + tableGoals + Referrers + getCampaigns + 1 + 1 + + widgetReferrersgetCampaignsviewDataTabletableGoalsdocumentationForGoalsPage1idGoal1 + tableGoals + 1 + + + Visits to Conversion + + Goals engagement + Goals engagement + 99 + + + Goals engagement + Goals engagement + 99 + + Goals + getVisitsUntilConversion + 101 + + Goals + getVisitsUntilConversion + 1 + 1 + + widgetGoalsgetVisitsUntilConversiondocumentationForGoalsPage1idGoal1 + table + 1 + + + Days to Conversion + + Goals engagement + Goals engagement + 99 + + + Goals engagement + Goals engagement + 99 + + Goals + getDaysToConversion + 102 + + Goals + getDaysToConversion + 1 + 1 + + widgetGoalsgetDaysToConversiondocumentationForGoalsPage1idGoal1 + table + 1 + + + + + + + Goals_Goals.2 + + Goals_Goals + Goals + 25 + + + 2 + Goal 2 - Hello + 901 + + + + Goal 2 - Hello + CoreHome + renderWidgetContainer + 20 + + CoreHome + renderWidgetContainer + Goal_2 + + widgetGoal_2 + + 1 + + + + + Goals_Goals + Goals + 99 + + + 2 + 2 + 99 + + Goals + getEvolutionGraph + 18 + + 1 + graphEvolution + Goals + getEvolutionGraph + 2 + + widgetGoalsgetEvolutionGraphforceView1viewDataTablegraphEvolutionidGoal2 + graphEvolution + 1 + + + + + Goals_Goals + Goals + 99 + + + 2 + 2 + 99 + + Goals + get + 19 + + 1 + sparklines + Goals + get + 2 + 0 + + widgetGoalsgetforceView1viewDataTablesparklinesidGoal2allow_multiple0 + sparklines + 1 + + + Conversions Overview + + Goals_Goals + Goals + 99 + + + 2 + 2 + 99 + + Goals + goalConversionsOverview + 20 + + Goals + goalConversionsOverview + 2 + + widgetGoalsgoalConversionsOverviewidGoal2 + + Goals + hasConversions + 2 + + table + 1 + + + + + Goal Goal 2 - Hello conversions by type of visit + CoreHome + renderWidgetContainer + 22 + + CoreHome + renderWidgetContainer + Goals2 + + widgetGoals2 + + Goals + hasConversions + 2 + + ByDimension + 1 + + + Custom Variables + + Goals by User attribute + Goals by User attribute + 99 + + + Goals by User attribute + Goals by User attribute + 99 + + CustomVariables + getCustomVariables + 301 + + tableGoals + CustomVariables + getCustomVariables + 1 + 2 + + widgetCustomVariablesgetCustomVariablesviewDataTabletableGoalsdocumentationForGoalsPage1idGoal2 + tableGoals + 1 + + + Visits per server time + + Goals by User attribute + Goals by User attribute + 99 + + + Goals by User attribute + Goals by User attribute + 99 + + VisitTime + getVisitInformationPerServerTime + 302 + + tableGoals + VisitTime + getVisitInformationPerServerTime + 1 + 2 + + widgetVisitTimegetVisitInformationPerServerTimeviewDataTabletableGoalsdocumentationForGoalsPage1idGoal2 + tableGoals + 1 + + + Country + + Goals by User location + Goals by User location + 99 + + + Goals by User location + Goals by User location + 99 + + UserCountry + getCountry + 201 + + tableGoals + UserCountry + getCountry + 1 + 2 + + widgetUserCountrygetCountryviewDataTabletableGoalsdocumentationForGoalsPage1idGoal2 + tableGoals + 1 + + + Continent + + Goals by User location + Goals by User location + 99 + + + Goals by User location + Goals by User location + 99 + + UserCountry + getContinent + 202 + + tableGoals + UserCountry + getContinent + 1 + 2 + + widgetUserCountrygetContinentviewDataTabletableGoalsdocumentationForGoalsPage1idGoal2 + tableGoals + 1 + + + Region + + Goals by User location + Goals by User location + 99 + + + Goals by User location + Goals by User location + 99 + + UserCountry + getRegion + 203 + + tableGoals + UserCountry + getRegion + 1 + 2 + + widgetUserCountrygetRegionviewDataTabletableGoalsdocumentationForGoalsPage1idGoal2 + tableGoals + 1 + + + City + + Goals by User location + Goals by User location + 99 + + + Goals by User location + Goals by User location + 99 + + UserCountry + getCity + 204 + + tableGoals + UserCountry + getCity + 1 + 2 + + widgetUserCountrygetCityviewDataTabletableGoalsdocumentationForGoalsPage1idGoal2 + tableGoals + 1 + + + Referrer Type + + Goals by Referrers + Goals by Referrers + 99 + + + Goals by Referrers + Goals by Referrers + 99 + + Referrers + getReferrerType + 1 + + tableGoals + Referrers + getReferrerType + 1 + 2 + + widgetReferrersgetReferrerTypeviewDataTabletableGoalsdocumentationForGoalsPage1idGoal2 + tableGoals + 1 + + + Keywords + + Goals by Referrers + Goals by Referrers + 99 + + + Goals by Referrers + Goals by Referrers + 99 + + Referrers + getKeywords + 2 + + tableGoals + Referrers + getKeywords + 1 + 2 + + widgetReferrersgetKeywordsviewDataTabletableGoalsdocumentationForGoalsPage1idGoal2 + tableGoals + 1 + + + Search Engines + + Goals by Referrers + Goals by Referrers + 99 + + + Goals by Referrers + Goals by Referrers + 99 + + Referrers + getSearchEngines + 3 + + tableGoals + Referrers + getSearchEngines + 1 + 2 + + widgetReferrersgetSearchEnginesviewDataTabletableGoalsdocumentationForGoalsPage1idGoal2 + tableGoals + 1 + + + Websites + + Goals by Referrers + Goals by Referrers + 99 + + + Goals by Referrers + Goals by Referrers + 99 + + Referrers + getWebsites + 4 + + tableGoals + Referrers + getWebsites + 1 + 2 + + widgetReferrersgetWebsitesviewDataTabletableGoalsdocumentationForGoalsPage1idGoal2 + tableGoals + 1 + + + Campaigns + + Goals by Referrers + Goals by Referrers + 99 + + + Goals by Referrers + Goals by Referrers + 99 + + Referrers + getCampaigns + 5 + + tableGoals + Referrers + getCampaigns + 1 + 2 + + widgetReferrersgetCampaignsviewDataTabletableGoalsdocumentationForGoalsPage1idGoal2 + tableGoals + 1 + + + Visits to Conversion + + Goals engagement + Goals engagement + 99 + + + Goals engagement + Goals engagement + 99 + + Goals + getVisitsUntilConversion + 101 + + Goals + getVisitsUntilConversion + 1 + 2 + + widgetGoalsgetVisitsUntilConversiondocumentationForGoalsPage1idGoal2 + table + 1 + + + Days to Conversion + + Goals engagement + Goals engagement + 99 + + + Goals engagement + Goals engagement + 99 + + Goals + getDaysToConversion + 102 + + Goals + getDaysToConversion + 1 + 2 + + widgetGoalsgetDaysToConversiondocumentationForGoalsPage1idGoal2 + table + 1 + + + + + + + Goals_Goals.3 + + Goals_Goals + Goals + 25 + + + 3 + triggered js + 902 + + + + triggered js + CoreHome + renderWidgetContainer + 25 + + CoreHome + renderWidgetContainer + Goal_3 + + widgetGoal_3 + + 1 + + + + + Goals_Goals + Goals + 99 + + + 3 + 3 + 99 + + Goals + getEvolutionGraph + 23 + + 1 + graphEvolution + Goals + getEvolutionGraph + 3 + + widgetGoalsgetEvolutionGraphforceView1viewDataTablegraphEvolutionidGoal3 + graphEvolution + 1 + + + + + Goals_Goals + Goals + 99 + + + 3 + 3 + 99 + + Goals + get + 24 + + 1 + sparklines + Goals + get + 3 + 0 + + widgetGoalsgetforceView1viewDataTablesparklinesidGoal3allow_multiple0 + sparklines + 1 + + + Conversions Overview + + Goals_Goals + Goals + 99 + + + 3 + 3 + 99 + + Goals + goalConversionsOverview + 25 + + Goals + goalConversionsOverview + 3 + + widgetGoalsgoalConversionsOverviewidGoal3 + + Goals + hasConversions + 3 + + table + 1 + + + + + Goal triggered js conversions by type of visit + CoreHome + renderWidgetContainer + 27 + + CoreHome + renderWidgetContainer + Goals3 + + widgetGoals3 + + Goals + hasConversions + 3 + + ByDimension + 1 + + + Custom Variables + + Goals by User attribute + Goals by User attribute + 99 + + + Goals by User attribute + Goals by User attribute + 99 + + CustomVariables + getCustomVariables + 301 + + tableGoals + CustomVariables + getCustomVariables + 1 + 3 + + widgetCustomVariablesgetCustomVariablesviewDataTabletableGoalsdocumentationForGoalsPage1idGoal3 + tableGoals + 1 + + + Visits per server time + + Goals by User attribute + Goals by User attribute + 99 + + + Goals by User attribute + Goals by User attribute + 99 + + VisitTime + getVisitInformationPerServerTime + 302 + + tableGoals + VisitTime + getVisitInformationPerServerTime + 1 + 3 + + widgetVisitTimegetVisitInformationPerServerTimeviewDataTabletableGoalsdocumentationForGoalsPage1idGoal3 + tableGoals + 1 + + + Country + + Goals by User location + Goals by User location + 99 + + + Goals by User location + Goals by User location + 99 + + UserCountry + getCountry + 201 + + tableGoals + UserCountry + getCountry + 1 + 3 + + widgetUserCountrygetCountryviewDataTabletableGoalsdocumentationForGoalsPage1idGoal3 + tableGoals + 1 + + + Continent + + Goals by User location + Goals by User location + 99 + + + Goals by User location + Goals by User location + 99 + + UserCountry + getContinent + 202 + + tableGoals + UserCountry + getContinent + 1 + 3 + + widgetUserCountrygetContinentviewDataTabletableGoalsdocumentationForGoalsPage1idGoal3 + tableGoals + 1 + + + Region + + Goals by User location + Goals by User location + 99 + + + Goals by User location + Goals by User location + 99 + + UserCountry + getRegion + 203 + + tableGoals + UserCountry + getRegion + 1 + 3 + + widgetUserCountrygetRegionviewDataTabletableGoalsdocumentationForGoalsPage1idGoal3 + tableGoals + 1 + + + City + + Goals by User location + Goals by User location + 99 + + + Goals by User location + Goals by User location + 99 + + UserCountry + getCity + 204 + + tableGoals + UserCountry + getCity + 1 + 3 + + widgetUserCountrygetCityviewDataTabletableGoalsdocumentationForGoalsPage1idGoal3 + tableGoals + 1 + + + Referrer Type + + Goals by Referrers + Goals by Referrers + 99 + + + Goals by Referrers + Goals by Referrers + 99 + + Referrers + getReferrerType + 1 + + tableGoals + Referrers + getReferrerType + 1 + 3 + + widgetReferrersgetReferrerTypeviewDataTabletableGoalsdocumentationForGoalsPage1idGoal3 + tableGoals + 1 + + + Keywords + + Goals by Referrers + Goals by Referrers + 99 + + + Goals by Referrers + Goals by Referrers + 99 + + Referrers + getKeywords + 2 + + tableGoals + Referrers + getKeywords + 1 + 3 + + widgetReferrersgetKeywordsviewDataTabletableGoalsdocumentationForGoalsPage1idGoal3 + tableGoals + 1 + + + Search Engines + + Goals by Referrers + Goals by Referrers + 99 + + + Goals by Referrers + Goals by Referrers + 99 + + Referrers + getSearchEngines + 3 + + tableGoals + Referrers + getSearchEngines + 1 + 3 + + widgetReferrersgetSearchEnginesviewDataTabletableGoalsdocumentationForGoalsPage1idGoal3 + tableGoals + 1 + + + Websites + + Goals by Referrers + Goals by Referrers + 99 + + + Goals by Referrers + Goals by Referrers + 99 + + Referrers + getWebsites + 4 + + tableGoals + Referrers + getWebsites + 1 + 3 + + widgetReferrersgetWebsitesviewDataTabletableGoalsdocumentationForGoalsPage1idGoal3 + tableGoals + 1 + + + Campaigns + + Goals by Referrers + Goals by Referrers + 99 + + + Goals by Referrers + Goals by Referrers + 99 + + Referrers + getCampaigns + 5 + + tableGoals + Referrers + getCampaigns + 1 + 3 + + widgetReferrersgetCampaignsviewDataTabletableGoalsdocumentationForGoalsPage1idGoal3 + tableGoals + 1 + + + Visits to Conversion + + Goals engagement + Goals engagement + 99 + + + Goals engagement + Goals engagement + 99 + + Goals + getVisitsUntilConversion + 101 + + Goals + getVisitsUntilConversion + 1 + 3 + + widgetGoalsgetVisitsUntilConversiondocumentationForGoalsPage1idGoal3 + table + 1 + + + Days to Conversion + + Goals engagement + Goals engagement + 99 + + + Goals engagement + Goals engagement + 99 + + Goals + getDaysToConversion + 102 + + Goals + getDaysToConversion + 1 + 3 + + widgetGoalsgetDaysToConversiondocumentationForGoalsPage1idGoal3 + table + 1 + + + + + + + Goals_Goals.General_Overview + + Goals_Goals + Goals + 25 + + + General_Overview + Overview + 2 + + + + Overview + CoreHome + renderWidgetContainer + 5 + + CoreHome + renderWidgetContainer + GoalsOverview + + widgetGoalsOverview + + 1 + + + + + Goals_Goals + Goals + 99 + + + General_Overview + Overview + 99 + + Goals + getEvolutionGraph + 1 + + 1 + graphEvolution + Goals + getEvolutionGraph + + widgetGoalsgetEvolutionGraphforceView1viewDataTablegraphEvolution + graphEvolution + 1 + + + + + Goals_Goals + Goals + 99 + + + General_Overview + Overview + 99 + + Goals + get + 2 + + 1 + sparklines + Goals + get + + widgetGoalsgetforceView1viewDataTablesparklines + sparklines + 1 + + + Goal Goal 1 - Thank you + + Goals_Goals + Goals + 99 + + + General_Overview + Overview + 99 + + Goals + get + 3 + + 1 + sparklines + Goals + get + 1 + 1 + 1 + + widgetGoalsgetforceView1viewDataTablesparklinesidGoal1allow_multiple1only_summary1 + sparklines + 1 + + + Goal Goal 2 - Hello + + Goals_Goals + Goals + 99 + + + General_Overview + Overview + 99 + + Goals + get + 4 + + 1 + sparklines + Goals + get + 2 + 0 + 1 + + widgetGoalsgetforceView1viewDataTablesparklinesidGoal2allow_multiple0only_summary1 + sparklines + 1 + + + Goal triggered js + + Goals_Goals + Goals + 99 + + + General_Overview + Overview + 99 + + Goals + get + 5 + + 1 + sparklines + Goals + get + 3 + 0 + 1 + + widgetGoalsgetforceView1viewDataTablesparklinesidGoal3allow_multiple0only_summary1 + sparklines + 1 + + + + + Conversions overview by type of visit + CoreHome + renderWidgetContainer + 7 + + CoreHome + renderWidgetContainer + Goals + + widgetGoals + + Goals + hasConversions + + ByDimension + 1 + + + Custom Variables + + Goals by User attribute + Goals by User attribute + 99 + + + Goals by User attribute + Goals by User attribute + 99 + + CustomVariables + getCustomVariables + 301 + + tableGoals + CustomVariables + getCustomVariables + 1 + 0 + + widgetCustomVariablesgetCustomVariablesviewDataTabletableGoalsdocumentationForGoalsPage1idGoal0 + tableGoals + 1 + + + Visits per server time + + Goals by User attribute + Goals by User attribute + 99 + + + Goals by User attribute + Goals by User attribute + 99 + + VisitTime + getVisitInformationPerServerTime + 302 + + tableGoals + VisitTime + getVisitInformationPerServerTime + 1 + 0 + + widgetVisitTimegetVisitInformationPerServerTimeviewDataTabletableGoalsdocumentationForGoalsPage1idGoal0 + tableGoals + 1 + + + Country + + Goals by User location + Goals by User location + 99 + + + Goals by User location + Goals by User location + 99 + + UserCountry + getCountry + 201 + + tableGoals + UserCountry + getCountry + 1 + 0 + + widgetUserCountrygetCountryviewDataTabletableGoalsdocumentationForGoalsPage1idGoal0 + tableGoals + 1 + + + Continent + + Goals by User location + Goals by User location + 99 + + + Goals by User location + Goals by User location + 99 + + UserCountry + getContinent + 202 + + tableGoals + UserCountry + getContinent + 1 + 0 + + widgetUserCountrygetContinentviewDataTabletableGoalsdocumentationForGoalsPage1idGoal0 + tableGoals + 1 + + + Region + + Goals by User location + Goals by User location + 99 + + + Goals by User location + Goals by User location + 99 + + UserCountry + getRegion + 203 + + tableGoals + UserCountry + getRegion + 1 + 0 + + widgetUserCountrygetRegionviewDataTabletableGoalsdocumentationForGoalsPage1idGoal0 + tableGoals + 1 + + + City + + Goals by User location + Goals by User location + 99 + + + Goals by User location + Goals by User location + 99 + + UserCountry + getCity + 204 + + tableGoals + UserCountry + getCity + 1 + 0 + + widgetUserCountrygetCityviewDataTabletableGoalsdocumentationForGoalsPage1idGoal0 + tableGoals + 1 + + + Referrer Type + + Goals by Referrers + Goals by Referrers + 99 + + + Goals by Referrers + Goals by Referrers + 99 + + Referrers + getReferrerType + 1 + + tableGoals + Referrers + getReferrerType + 1 + 0 + + widgetReferrersgetReferrerTypeviewDataTabletableGoalsdocumentationForGoalsPage1idGoal0 + tableGoals + 1 + + + Keywords + + Goals by Referrers + Goals by Referrers + 99 + + + Goals by Referrers + Goals by Referrers + 99 + + Referrers + getKeywords + 2 + + tableGoals + Referrers + getKeywords + 1 + 0 + + widgetReferrersgetKeywordsviewDataTabletableGoalsdocumentationForGoalsPage1idGoal0 + tableGoals + 1 + + + Search Engines + + Goals by Referrers + Goals by Referrers + 99 + + + Goals by Referrers + Goals by Referrers + 99 + + Referrers + getSearchEngines + 3 + + tableGoals + Referrers + getSearchEngines + 1 + 0 + + widgetReferrersgetSearchEnginesviewDataTabletableGoalsdocumentationForGoalsPage1idGoal0 + tableGoals + 1 + + + Websites + + Goals by Referrers + Goals by Referrers + 99 + + + Goals by Referrers + Goals by Referrers + 99 + + Referrers + getWebsites + 4 + + tableGoals + Referrers + getWebsites + 1 + 0 + + widgetReferrersgetWebsitesviewDataTabletableGoalsdocumentationForGoalsPage1idGoal0 + tableGoals + 1 + + + Campaigns + + Goals by Referrers + Goals by Referrers + 99 + + + Goals by Referrers + Goals by Referrers + 99 + + Referrers + getCampaigns + 5 + + tableGoals + Referrers + getCampaigns + 1 + 0 + + widgetReferrersgetCampaignsviewDataTabletableGoalsdocumentationForGoalsPage1idGoal0 + tableGoals + 1 + + + Visits to Conversion + + Goals engagement + Goals engagement + 99 + + + Goals engagement + Goals engagement + 99 + + Goals + getVisitsUntilConversion + 101 + + Goals + getVisitsUntilConversion + 1 + 0 + + widgetGoalsgetVisitsUntilConversiondocumentationForGoalsPage1idGoal0 + table + 1 + + + Days to Conversion + + Goals engagement + Goals engagement + 99 + + + Goals engagement + Goals engagement + 99 + + Goals + getDaysToConversion + 102 + + Goals + getDaysToConversion + 1 + 0 + + widgetGoalsgetDaysToConversiondocumentationForGoalsPage1idGoal0 + table + 1 + + + + + + + Goals_Goals.Goals_ManageGoals + + Goals_Goals + Goals + 25 + + + Goals_ManageGoals + Manage Goals + 9999 + + + + Manage Goals + Goals + editGoals + 99 + + Goals + editGoals + + widgetGoalseditGoals + + + + + Goals_Ecommerce.Goals_EcommerceLog + + Goals_Ecommerce + Ecommerce + 20 + + + Goals_EcommerceLog + Ecommerce Log + 5 + + + + Ecommerce Log + Ecommerce + getEcommerceLog + 99 + + Ecommerce + getEcommerceLog + + widgetEcommercegetEcommerceLog + + + + + Goals_Ecommerce.General_Overview + + Goals_Ecommerce + Ecommerce + 20 + + + General_Overview + Overview + 2 + + + + Overview + CoreHome + renderWidgetContainer + 10 + + CoreHome + renderWidgetContainer + EcommerceOverview + + widgetEcommerceOverview + + 1 + + + + + Goals_Ecommerce + Ecommerce + 99 + + + General_Overview + Overview + 99 + + Goals + getEvolutionGraph + 8 + + 1 + graphEvolution + Goals + getEvolutionGraph + ecommerceOrder + + widgetGoalsgetEvolutionGraphforceView1viewDataTablegraphEvolutionidGoalecommerceOrder + graphEvolution + 1 + + + + + Goals_Ecommerce + Ecommerce + 99 + + + General_Overview + Overview + 99 + + Ecommerce + getSparklines + 9 + + 1 + sparklines + Ecommerce + getSparklines + ecommerceOrder + + widgetEcommercegetSparklinesforceView1viewDataTablesparklinesidGoalecommerceOrder + sparklines + 1 + + + Conversions Overview + + Goals_Goals + Goals + 99 + + + ecommerceOrder + ecommerceOrder + 99 + + Ecommerce + getConversionsOverview + 10 + + Ecommerce + getConversionsOverview + ecommerceOrder + + widgetEcommercegetConversionsOverviewidGoalecommerceOrder + + Goals + hasConversions + ecommerceOrder + + table + 1 + + + + + + + Goals_Ecommerce.Goals_Products + + Goals_Ecommerce + Ecommerce + 20 + + + Goals_Products + Products + 10 + + + + + CoreHome + renderWidgetContainer + 99 + + CoreHome + renderWidgetContainer + Products + + widgetProducts + ByDimension + 1 + + + Product SKU + + Goals_Ecommerce + Ecommerce + 99 + + + Goals_Products + Products + 99 + + Goals + getItemsSku + 130 + + Goals + getItemsSku + + widgetGoalsgetItemsSku + table + 1 + + + Product Name + + Goals_Ecommerce + Ecommerce + 99 + + + Goals_Products + Products + 99 + + Goals + getItemsName + 131 + + Goals + getItemsName + + widgetGoalsgetItemsName + table + 1 + + + Product Category + + Goals_Ecommerce + Ecommerce + 99 + + + Goals_Products + Products + 99 + + Goals + getItemsCategory + 132 + + Goals + getItemsCategory + + widgetGoalsgetItemsCategory + table + 1 + + + + + + + Goals_Ecommerce.Ecommerce_Sales + + Goals_Ecommerce + Ecommerce + 20 + + + Ecommerce_Sales + Sales + 15 + + + + + CoreHome + renderWidgetContainer + 12 + + CoreHome + renderWidgetContainer + ecommerceOrder + GoalsOrder + + widgetGoalsOrderidGoalecommerceOrder + ByDimension + 1 + + + Custom Variables + + Sales by User attribute + Sales by User attribute + 99 + + + Sales by User attribute + Sales by User attribute + 99 + + CustomVariables + getCustomVariables + 301 + + tableGoals + CustomVariables + getCustomVariables + 1 + ecommerceOrder + + widgetCustomVariablesgetCustomVariablesviewDataTabletableGoalsdocumentationForGoalsPage1idGoalecommerceOrder + tableGoals + 1 + + + Visits per server time + + Sales by User attribute + Sales by User attribute + 99 + + + Sales by User attribute + Sales by User attribute + 99 + + VisitTime + getVisitInformationPerServerTime + 302 + + tableGoals + VisitTime + getVisitInformationPerServerTime + 1 + ecommerceOrder + + widgetVisitTimegetVisitInformationPerServerTimeviewDataTabletableGoalsdocumentationForGoalsPage1idGoalecommerceOrder + tableGoals + 1 + + + Country + + Sales by User location + Sales by User location + 99 + + + Sales by User location + Sales by User location + 99 + + UserCountry + getCountry + 201 + + tableGoals + UserCountry + getCountry + 1 + ecommerceOrder + + widgetUserCountrygetCountryviewDataTabletableGoalsdocumentationForGoalsPage1idGoalecommerceOrder + tableGoals + 1 + + + Continent + + Sales by User location + Sales by User location + 99 + + + Sales by User location + Sales by User location + 99 + + UserCountry + getContinent + 202 + + tableGoals + UserCountry + getContinent + 1 + ecommerceOrder + + widgetUserCountrygetContinentviewDataTabletableGoalsdocumentationForGoalsPage1idGoalecommerceOrder + tableGoals + 1 + + + Region + + Sales by User location + Sales by User location + 99 + + + Sales by User location + Sales by User location + 99 + + UserCountry + getRegion + 203 + + tableGoals + UserCountry + getRegion + 1 + ecommerceOrder + + widgetUserCountrygetRegionviewDataTabletableGoalsdocumentationForGoalsPage1idGoalecommerceOrder + tableGoals + 1 + + + City + + Sales by User location + Sales by User location + 99 + + + Sales by User location + Sales by User location + 99 + + UserCountry + getCity + 204 + + tableGoals + UserCountry + getCity + 1 + ecommerceOrder + + widgetUserCountrygetCityviewDataTabletableGoalsdocumentationForGoalsPage1idGoalecommerceOrder + tableGoals + 1 + + + Referrer Type + + Sales by Referrers + Sales by Referrers + 99 + + + Sales by Referrers + Sales by Referrers + 99 + + Referrers + getReferrerType + 1 + + tableGoals + Referrers + getReferrerType + 1 + ecommerceOrder + + widgetReferrersgetReferrerTypeviewDataTabletableGoalsdocumentationForGoalsPage1idGoalecommerceOrder + tableGoals + 1 + + + Keywords + + Sales by Referrers + Sales by Referrers + 99 + + + Sales by Referrers + Sales by Referrers + 99 + + Referrers + getKeywords + 2 + + tableGoals + Referrers + getKeywords + 1 + ecommerceOrder + + widgetReferrersgetKeywordsviewDataTabletableGoalsdocumentationForGoalsPage1idGoalecommerceOrder + tableGoals + 1 + + + Search Engines + + Sales by Referrers + Sales by Referrers + 99 + + + Sales by Referrers + Sales by Referrers + 99 + + Referrers + getSearchEngines + 3 + + tableGoals + Referrers + getSearchEngines + 1 + ecommerceOrder + + widgetReferrersgetSearchEnginesviewDataTabletableGoalsdocumentationForGoalsPage1idGoalecommerceOrder + tableGoals + 1 + + + Websites + + Sales by Referrers + Sales by Referrers + 99 + + + Sales by Referrers + Sales by Referrers + 99 + + Referrers + getWebsites + 4 + + tableGoals + Referrers + getWebsites + 1 + ecommerceOrder + + widgetReferrersgetWebsitesviewDataTabletableGoalsdocumentationForGoalsPage1idGoalecommerceOrder + tableGoals + 1 + + + Campaigns + + Sales by Referrers + Sales by Referrers + 99 + + + Sales by Referrers + Sales by Referrers + 99 + + Referrers + getCampaigns + 5 + + tableGoals + Referrers + getCampaigns + 1 + ecommerceOrder + + widgetReferrersgetCampaignsviewDataTabletableGoalsdocumentationForGoalsPage1idGoalecommerceOrder + tableGoals + 1 + + + Visits to Conversion + + Sales engagement + Sales engagement + 99 + + + Sales engagement + Sales engagement + 99 + + Goals + getVisitsUntilConversion + 101 + + Goals + getVisitsUntilConversion + 1 + ecommerceOrder + + widgetGoalsgetVisitsUntilConversiondocumentationForGoalsPage1idGoalecommerceOrder + table + 1 + + + Days to Conversion + + Sales engagement + Sales engagement + 99 + + + Sales engagement + Sales engagement + 99 + + Goals + getDaysToConversion + 102 + + Goals + getDaysToConversion + 1 + ecommerceOrder + + widgetGoalsgetDaysToConversiondocumentationForGoalsPage1idGoalecommerceOrder + table + 1 + + + + + + + ExampleUI_UiFramework.ExampleUI_GetTemperaturesDataTable + + ExampleUI_UiFramework + UI Framework + 90 + + + ExampleUI_GetTemperaturesDataTable + Data tables + 99 + + + + Data tables + ExampleUI + getTemperatures + 210 + + ExampleUI + getTemperatures + + widgetExampleUIgetTemperatures + table + 1 + + + + + ExampleUI_UiFramework.Bar graph + + ExampleUI_UiFramework + UI Framework + 90 + + + Bar graph + Bar graph + 99 + + + + Data tables + ExampleUI + getTemperatures + 210 + + 1 + graphVerticalBar + ExampleUI + getTemperatures + + widgetExampleUIgetTemperaturesforceView1viewDataTablegraphVerticalBar + graphVerticalBar + 1 + + + + + ExampleUI_UiFramework.Treemap + + ExampleUI_UiFramework + UI Framework + 90 + + + Treemap + Treemap + 99 + + + + Treemap example + ExampleUI + getTemperatures + 210 + + 1 + infoviz-treemap + ExampleUI + getTemperatures + + widgetExampleUIgetTemperaturesforceView1viewDataTableinfoviz-treemap + infoviz-treemap + 1 + + + + + ExampleUI_UiFramework.Sparklines + + ExampleUI_UiFramework + UI Framework + 90 + + + Sparklines + Sparklines + 99 + + + + Temperatures evolution over time + ExampleUI + getTemperaturesEvolution + 211 + + 1 + sparklines + ExampleUI + getTemperaturesEvolution + + widgetExampleUIgetTemperaturesEvolutionforceView1viewDataTablesparklines + sparklines + 1 + + + + + ExampleUI_UiFramework.Evolution Graph + + ExampleUI_UiFramework + UI Framework + 90 + + + Evolution Graph + Evolution Graph + 99 + + + + Evolution of server temperatures over the last few days + ExampleUI + getTemperaturesEvolution + 211 + + 1 + graphEvolution + ExampleUI + getTemperaturesEvolution + + server1 + server2 + + + widgetExampleUIgetTemperaturesEvolutionforceView1viewDataTablegraphEvolutioncolumnsArray + graphEvolution + 1 + + + + + ExampleUI_UiFramework.Pie graph + + ExampleUI_UiFramework + UI Framework + 90 + + + Pie graph + Pie graph + 99 + + + + Pie graph + ExampleUI + getPlanetRatios + 212 + + graphPie + ExampleUI + getPlanetRatios + + widgetExampleUIgetPlanetRatiosviewDataTablegraphPie + graphPie + 1 + + + + + ExampleUI_UiFramework.Tag clouds + + ExampleUI_UiFramework + UI Framework + 90 + + + Tag clouds + Tag clouds + 99 + + + + Simple tag cloud + ExampleUI + getPlanetRatios + 5 + + 1 + cloud + ExampleUI + getPlanetRatios + + widgetExampleUIgetPlanetRatiosforceView1viewDataTablecloud + cloud + 1 + + + Advanced tag cloud: with logos and links + ExampleUI + getPlanetRatiosWithLogos + 213 + + cloud + ExampleUI + getPlanetRatiosWithLogos + + widgetExampleUIgetPlanetRatiosWithLogosviewDataTablecloud + cloud + 1 + + + + \ No newline at end of file diff --git a/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getWidgetMetadata.xml b/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getWidgetMetadata.xml new file mode 100644 index 0000000000..5ac9f04dd7 --- /dev/null +++ b/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getWidgetMetadata.xml @@ -0,0 +1,2694 @@ + + + + Real Time Visitor Count + + Live! + Live! + 2 + + + Live + getSimpleLastVisitCount + 15 + + Live + getSimpleLastVisitCount + + widgetLivegetSimpleLastVisitCount + table + 1 + + + Visitors in Real-time + + Live! + Live! + 2 + + + Live + widget + 20 + + Live + widget + + widgetLivewidget + + + Visits Overview + + General_Visitors + Visitors + 5 + + + General_Overview + Overview + 2 + + VisitsSummary + get + 10 + + 1 + sparklines + VisitsSummary + get + + widgetVisitsSummarygetforceView1viewDataTablesparklines + sparklines + 1 + + + Visits Over Time + + General_Visitors + Visitors + 5 + + + General_Overview + Overview + 2 + + VisitsSummary + getEvolutionGraph + 5 + + 1 + graphEvolution + VisitsSummary + getEvolutionGraph + + widgetVisitsSummarygetEvolutionGraphforceView1viewDataTablegraphEvolution + graphEvolution + 1 + + + Visitor Log + + General_Visitors + Visitors + 5 + + + Live_VisitorLog + Visitor Log + 5 + + Live + getLastVisitsDetails + 10 + + 1 + Piwik\Plugins\Live\VisitorLog + Live + getLastVisitsDetails + 1 + + widgetLivegetLastVisitsDetailsforceView1viewDataTablePiwik%5CPlugins%5CLive%5CVisitorLogsmall1 + Piwik\Plugins\Live\VisitorLog + 1 + + + Custom Variables + + General_Visitors + Visitors + 5 + + + CustomVariables_CustomVariables + Custom Variables + 10 + + CustomVariables + getCustomVariables + 110 + + CustomVariables + getCustomVariables + + widgetCustomVariablesgetCustomVariables + table + 1 + + + Screen Resolution + + General_Visitors + Visitors + 5 + + + DevicesDetection_Devices + Devices + 15 + + Resolution + getResolution + 108 + + Resolution + getResolution + + widgetResolutiongetResolution + table + 1 + + + Device type + + General_Visitors + Visitors + 5 + + + DevicesDetection_Devices + Devices + 15 + + DevicesDetection + getType + 100 + + DevicesDetection + getType + + widgetDevicesDetectiongetType + table + 1 + + + Device brand + + General_Visitors + Visitors + 5 + + + DevicesDetection_Devices + Devices + 15 + + DevicesDetection + getBrand + 104 + + DevicesDetection + getBrand + + widgetDevicesDetectiongetBrand + table + 1 + + + Device model + + General_Visitors + Visitors + 5 + + + DevicesDetection_Devices + Devices + 15 + + DevicesDetection + getModel + 102 + + DevicesDetection + getModel + + widgetDevicesDetectiongetModel + table + 1 + + + Browsers + + General_Visitors + Visitors + 5 + + + DevicesDetection_Software + Software + 20 + + DevicesDetection + getBrowsers + 105 + + DevicesDetection + getBrowsers + + widgetDevicesDetectiongetBrowsers + table + 1 + + + Operating System versions + + General_Visitors + Visitors + 5 + + + DevicesDetection_Software + Software + 20 + + DevicesDetection + getOsVersions + 102 + + DevicesDetection + getOsVersions + + widgetDevicesDetectiongetOsVersions + table + 1 + + + Browser version + + General_Visitors + Visitors + 5 + + + DevicesDetection_Software + Software + 20 + + DevicesDetection + getBrowserVersions + 106 + + DevicesDetection + getBrowserVersions + + widgetDevicesDetectiongetBrowserVersions + table + 1 + + + Browser Plugins + + General_Visitors + Visitors + 5 + + + DevicesDetection_Software + Software + 20 + + DevicePlugins + getPlugin + 113 + + DevicePlugins + getPlugin + + widgetDevicePluginsgetPlugin + table + 1 + + + Operating System families + + General_Visitors + Visitors + 5 + + + DevicesDetection_Software + Software + 20 + + DevicesDetection + getOsFamilies + 108 + + DevicesDetection + getOsFamilies + + widgetDevicesDetectiongetOsFamilies + table + 1 + + + Browser engines + + General_Visitors + Visitors + 5 + + + DevicesDetection_Software + Software + 20 + + DevicesDetection + getBrowserEngines + 110 + + graphPie + DevicesDetection + getBrowserEngines + + widgetDevicesDetectiongetBrowserEnginesviewDataTablegraphPie + graphPie + 1 + + + Configurations + + General_Visitors + Visitors + 5 + + + DevicesDetection_Software + Software + 20 + + Resolution + getConfiguration + 107 + + Resolution + getConfiguration + + widgetResolutiongetConfiguration + table + 1 + + + Language code + + General_Visitors + Visitors + 5 + + + UserCountry_SubmenuLocations + Locations + 25 + + UserLanguage + getLanguageCode + 111 + + UserLanguage + getLanguageCode + + widgetUserLanguagegetLanguageCode + table + 1 + + + Providers + + General_Visitors + Visitors + 5 + + + UserCountry_SubmenuLocations + Locations + 25 + + Provider + getProvider + 150 + + Provider + getProvider + + widgetProvidergetProvider + table + 1 + + + City + + General_Visitors + Visitors + 5 + + + UserCountry_SubmenuLocations + Locations + 25 + + UserCountry + getCity + 110 + + UserCountry + getCity + + widgetUserCountrygetCity + table + 1 + + + Continent + + General_Visitors + Visitors + 5 + + + UserCountry_SubmenuLocations + Locations + 25 + + UserCountry + getContinent + 106 + + UserCountry + getContinent + + widgetUserCountrygetContinent + table + 1 + + + Visitor Map + + General_Visitors + Visitors + 5 + + + UserCountry_SubmenuLocations + Locations + 25 + + UserCountryMap + visitorMap + 1 + + UserCountryMap + visitorMap + + widgetUserCountryMapvisitorMap + + + Region + + General_Visitors + Visitors + 5 + + + UserCountry_SubmenuLocations + Locations + 25 + + UserCountry + getRegion + 107 + + UserCountry + getRegion + + widgetUserCountrygetRegion + table + 1 + + + Browser language + + General_Visitors + Visitors + 5 + + + UserCountry_SubmenuLocations + Locations + 25 + + UserLanguage + getLanguage + 108 + + UserLanguage + getLanguage + + widgetUserLanguagegetLanguage + table + 1 + + + Visits Overview (with graph) + + General_Visitors + Visitors + 5 + + + CoreHome + renderWidgetContainer + 99 + + CoreHome + renderWidgetContainer + VisitOverviewWithGraph + + widgetVisitOverviewWithGraph + + 1 + + + Visits Over Time + + General_Visitors + Visitors + 99 + + + General_Overview + Overview + 99 + + VisitsSummary + getEvolutionGraph + 5 + + 1 + graphEvolution + VisitsSummary + getEvolutionGraph + + widgetVisitsSummarygetEvolutionGraphforceView1viewDataTablegraphEvolution + graphEvolution + 1 + + + Visits Overview + + General_Visitors + Visitors + 99 + + + General_Overview + Overview + 99 + + VisitsSummary + get + 10 + + 1 + sparklines + VisitsSummary + get + + widgetVisitsSummarygetforceView1viewDataTablesparklines + sparklines + 1 + + + + + Country + + General_Visitors + Visitors + 5 + + + UserCountry_SubmenuLocations + Locations + 25 + + UserCountry + getCountry + 105 + + UserCountry + getCountry + + widgetUserCountrygetCountry + table + 1 + + + Visits by Visit Number + + General_Visitors + Visitors + 5 + + + VisitorInterest_Engagement + Engagement + 30 + + VisitorInterest + getNumberOfVisitsByVisitCount + 125 + + VisitorInterest + getNumberOfVisitsByVisitCount + + widgetVisitorInterestgetNumberOfVisitsByVisitCount + table + 1 + + + Visitor profile + + General_Visitors + Visitors + 5 + + + Live + getVisitorProfilePopup + 25 + + Live + getVisitorProfilePopup + + widgetLivegetVisitorProfilePopup + + + Visits by Days Since Last Visit + + General_Visitors + Visitors + 5 + + + VisitorInterest_Engagement + Engagement + 30 + + VisitorInterest + getNumberOfVisitsByDaysSinceLast + 130 + + VisitorInterest + getNumberOfVisitsByDaysSinceLast + + widgetVisitorInterestgetNumberOfVisitsByDaysSinceLast + table + 1 + + + Visits per number of pages + + General_Visitors + Visitors + 5 + + + VisitorInterest_Engagement + Engagement + 30 + + VisitorInterest + getNumberOfVisitsPerPage + 120 + + cloud + VisitorInterest + getNumberOfVisitsPerPage + + widgetVisitorInterestgetNumberOfVisitsPerPageviewDataTablecloud + cloud + 1 + + + Returning Visits Over Time + + General_Visitors + Visitors + 5 + + + VisitorInterest_Engagement + Engagement + 30 + + VisitFrequency + getEvolutionGraph + 1 + + 1 + graphEvolution + VisitFrequency + getEvolutionGraph + + widgetVisitFrequencygetEvolutionGraphforceView1viewDataTablegraphEvolution + graphEvolution + 1 + + + Frequency Overview + + General_Visitors + Visitors + 5 + + + VisitorInterest_Engagement + Engagement + 30 + + VisitFrequency + get + 2 + + 1 + sparklines + VisitFrequency + get + + widgetVisitFrequencygetforceView1viewDataTablesparklines + sparklines + 1 + + + Visits per visit duration + + General_Visitors + Visitors + 5 + + + VisitorInterest_Engagement + Engagement + 30 + + VisitorInterest + getNumberOfVisitsPerVisitDuration + 115 + + cloud + VisitorInterest + getNumberOfVisitsPerVisitDuration + + widgetVisitorInterestgetNumberOfVisitsPerVisitDurationviewDataTablecloud + cloud + 1 + + + Visits by Day of Week + + General_Visitors + Visitors + 5 + + + VisitTime_SubmenuTimes + Times + 35 + + VisitTime + getByDayOfWeek + 125 + + graphVerticalBar + VisitTime + getByDayOfWeek + + widgetVisitTimegetByDayOfWeekviewDataTablegraphVerticalBar + graphVerticalBar + 1 + + + Visits per server time + + General_Visitors + Visitors + 5 + + + VisitTime_SubmenuTimes + Times + 35 + + VisitTime + getVisitInformationPerServerTime + 120 + + graphVerticalBar + VisitTime + getVisitInformationPerServerTime + + widgetVisitTimegetVisitInformationPerServerTimeviewDataTablegraphVerticalBar + graphVerticalBar + 1 + + + Visits per local time + + General_Visitors + Visitors + 5 + + + VisitTime_SubmenuTimes + Times + 35 + + VisitTime + getVisitInformationPerLocalTime + 115 + + graphVerticalBar + VisitTime + getVisitInformationPerLocalTime + + widgetVisitTimegetVisitInformationPerLocalTimeviewDataTablegraphVerticalBar + graphVerticalBar + 1 + + + Real-time Map + + General_Visitors + Visitors + 5 + + + UserCountryMap_RealTimeMap + Real-time Map + 40 + + UserCountryMap + realtimeMap + 5 + + UserCountryMap + realtimeMap + + widgetUserCountryMaprealtimeMap + + + Pages + + General_Actions + Actions + 10 + + + General_Pages + Pages + 5 + + Actions + getPageUrls + 102 + + Actions + getPageUrls + + widgetActionsgetPageUrls + table + 1 + + + Entry pages + + General_Actions + Actions + 10 + + + Actions_SubmenuPagesEntry + Entry pages + 10 + + Actions + getEntryPageUrls + 103 + + Actions + getEntryPageUrls + + widgetActionsgetEntryPageUrls + table + 1 + + + Exit pages + + General_Actions + Actions + 10 + + + Actions_SubmenuPagesExit + Exit pages + 15 + + Actions + getExitPageUrls + 104 + + Actions + getExitPageUrls + + widgetActionsgetExitPageUrls + table + 1 + + + Page titles + + General_Actions + Actions + 10 + + + Actions_SubmenuPageTitles + Page titles + 20 + + Actions + getPageTitles + 105 + + Actions + getPageTitles + + widgetActionsgetPageTitles + table + 1 + + + Pages Following a Site Search + + General_Actions + Actions + 10 + + + Actions_SubmenuSitesearch + Site Search + 25 + + Actions + getPageUrlsFollowingSiteSearch + 116 + + Actions + getPageUrlsFollowingSiteSearch + + widgetActionsgetPageUrlsFollowingSiteSearch + table + 1 + + + Search Keywords with No Results + + General_Actions + Actions + 10 + + + Actions_SubmenuSitesearch + Site Search + 25 + + Actions + getSiteSearchNoResultKeywords + 118 + + Actions + getSiteSearchNoResultKeywords + + widgetActionsgetSiteSearchNoResultKeywords + table + 1 + + + Page Titles Following a Site Search + + General_Actions + Actions + 10 + + + Actions_SubmenuSitesearch + Site Search + 25 + + Actions + getPageTitlesFollowingSiteSearch + 119 + + Actions + getPageTitlesFollowingSiteSearch + + widgetActionsgetPageTitlesFollowingSiteSearch + table + 1 + + + Search Categories + + General_Actions + Actions + 10 + + + Actions_SubmenuSitesearch + Site Search + 25 + + Actions + getSiteSearchCategories + 120 + + Actions + getSiteSearchCategories + + widgetActionsgetSiteSearchCategories + table + 1 + + + Site Search Keywords + + General_Actions + Actions + 10 + + + Actions_SubmenuSitesearch + Site Search + 25 + + Actions + getSiteSearchKeywords + 115 + + Actions + getSiteSearchKeywords + + widgetActionsgetSiteSearchKeywords + table + 1 + + + Outlinks + + General_Actions + Actions + 10 + + + General_Outlinks + Outlinks + 30 + + Actions + getOutlinks + 108 + + Actions + getOutlinks + + widgetActionsgetOutlinks + table + 1 + + + Downloads + + General_Actions + Actions + 10 + + + General_Downloads + Downloads + 35 + + Actions + getDownloads + 109 + + Actions + getDownloads + + widgetActionsgetDownloads + table + 1 + + + Event Categories + + General_Actions + Actions + 10 + + + Events_Events + Events + 40 + + Events + getCategory + 100 + + Events + getCategory + eventAction + + widgetEventsgetCategorysecondaryDimensioneventAction + table + 1 + + + Event Actions + + General_Actions + Actions + 10 + + + Events_Events + Events + 40 + + Events + getAction + 101 + + Events + getAction + eventName + + widgetEventsgetActionsecondaryDimensioneventName + table + 1 + + + Event Actions + + General_Actions + Actions + 10 + + + Events_Events + Events + 40 + + Events + getAction + 101 + + Events + getAction + eventName + + widgetEventsgetActionsecondaryDimensioneventName + table + 1 + + + Event Names + + General_Actions + Actions + 10 + + + Events_Events + Events + 40 + + Events + getName + 102 + + Events + getName + eventAction + + widgetEventsgetNamesecondaryDimensioneventAction + table + 1 + + + Event Names + + General_Actions + Actions + 10 + + + Events_Events + Events + 40 + + Events + getName + 102 + + Events + getName + eventAction + + widgetEventsgetNamesecondaryDimensioneventAction + table + 1 + + + Entry Page Titles + + General_Actions + Actions + 10 + + + Actions + getEntryPageTitles + 106 + + Actions + getEntryPageTitles + + widgetActionsgetEntryPageTitles + table + 1 + + + Event Categories + + General_Actions + Actions + 10 + + + Events_Events + Events + 40 + + Events + getCategory + 100 + + Events + getCategory + eventAction + + widgetEventsgetCategorysecondaryDimensioneventAction + table + 1 + + + Content Piece + + General_Actions + Actions + 10 + + + Contents_Contents + Contents + 45 + + Contents + getContentPieces + 136 + + Contents + getContentPieces + + widgetContentsgetContentPieces + table + 1 + + + Content Piece + + General_Actions + Actions + 10 + + + Contents_Contents + Contents + 45 + + Contents + getContentPieces + 136 + + Contents + getContentPieces + + widgetContentsgetContentPieces + table + 1 + + + Exit page titles + + General_Actions + Actions + 10 + + + Actions + getExitPageTitles + 107 + + Actions + getExitPageTitles + + widgetActionsgetExitPageTitles + table + 1 + + + Content Name + + General_Actions + Actions + 10 + + + Contents_Contents + Contents + 45 + + Contents + getContentNames + 135 + + Contents + getContentNames + + widgetContentsgetContentNames + table + 1 + + + Content Name + + General_Actions + Actions + 10 + + + Contents_Contents + Contents + 45 + + Contents + getContentNames + 135 + + Contents + getContentNames + + widgetContentsgetContentNames + table + 1 + + + Referrers + + Referrers_Referrers + Referrers + 15 + + + Referrers_WidgetGetAll + All Referrers + 5 + + Referrers + getAll + 102 + + tableAllColumns + Referrers + getAll + + widgetReferrersgetAllviewDataTabletableAllColumns + tableAllColumns + 1 + + + Referrer Types + + Referrers_Referrers + Referrers + 15 + + + Referrers_WidgetGetAll + All Referrers + 5 + + Referrers + getReferrerType + 101 + + tableAllColumns + Referrers + getReferrerType + + widgetReferrersgetReferrerTypeviewDataTabletableAllColumns + tableAllColumns + 1 + + + Search Engines + + Referrers_Referrers + Referrers + 15 + + + Referrers_SubmenuSearchEngines + Search Engines & Keywords + 10 + + Referrers + getSearchEngines + 107 + + Referrers + getSearchEngines + + widgetReferrersgetSearchEngines + table + 1 + + + Keywords + + Referrers_Referrers + Referrers + 15 + + + Referrers_SubmenuSearchEngines + Search Engines & Keywords + 10 + + Referrers + getKeywords + 103 + + Referrers + getKeywords + + widgetReferrersgetKeywords + table + 1 + + + Social Networks + + Referrers_Referrers + Referrers + 15 + + + Referrers_SubmenuWebsites + Websites & Social + 15 + + Referrers + getSocials + 111 + + graphPie + Referrers + getSocials + + widgetReferrersgetSocialsviewDataTablegraphPie + graphPie + 1 + + + Websites + + Referrers_Referrers + Referrers + 15 + + + Referrers_SubmenuWebsites + Websites & Social + 15 + + Referrers + getWebsites + 105 + + Referrers + getWebsites + + widgetReferrersgetWebsites + table + 1 + + + Campaigns + + Referrers_Referrers + Referrers + 15 + + + Referrers_Campaigns + Campaigns + 20 + + Referrers + getCampaigns + 109 + + Referrers + getCampaigns + + widgetReferrersgetCampaigns + table + 1 + + + Overview + + Goals_Ecommerce + Ecommerce + 20 + + + General_Overview + Overview + 2 + + CoreHome + renderWidgetContainer + 10 + + CoreHome + renderWidgetContainer + EcommerceOverview + + widgetEcommerceOverview + + 1 + + + + + Goals_Ecommerce + Ecommerce + 99 + + + General_Overview + Overview + 99 + + Goals + getEvolutionGraph + 8 + + 1 + graphEvolution + Goals + getEvolutionGraph + ecommerceOrder + + widgetGoalsgetEvolutionGraphforceView1viewDataTablegraphEvolutionidGoalecommerceOrder + graphEvolution + 1 + + + + + Goals_Ecommerce + Ecommerce + 99 + + + General_Overview + Overview + 99 + + Ecommerce + getSparklines + 9 + + 1 + sparklines + Ecommerce + getSparklines + ecommerceOrder + + widgetEcommercegetSparklinesforceView1viewDataTablesparklinesidGoalecommerceOrder + sparklines + 1 + + + Conversions Overview + + Goals_Goals + Goals + 99 + + + ecommerceOrder + ecommerceOrder + 99 + + Ecommerce + getConversionsOverview + 10 + + Ecommerce + getConversionsOverview + ecommerceOrder + + widgetEcommercegetConversionsOverviewidGoalecommerceOrder + + Goals + hasConversions + ecommerceOrder + + table + 1 + + + + + Ecommerce Log + + Goals_Ecommerce + Ecommerce + 20 + + + Goals_EcommerceLog + Ecommerce Log + 5 + + Ecommerce + getEcommerceLog + 99 + + Ecommerce + getEcommerceLog + + widgetEcommercegetEcommerceLog + + + Product SKU + + Goals_Ecommerce + Ecommerce + 20 + + + Goals_Products + Products + 10 + + Goals + getItemsSku + 130 + + Goals + getItemsSku + + widgetGoalsgetItemsSku + table + 1 + + + Product Name + + Goals_Ecommerce + Ecommerce + 20 + + + Goals_Products + Products + 10 + + Goals + getItemsName + 131 + + Goals + getItemsName + + widgetGoalsgetItemsName + table + 1 + + + Product Category + + Goals_Ecommerce + Ecommerce + 20 + + + Goals_Products + Products + 10 + + Goals + getItemsCategory + 132 + + Goals + getItemsCategory + + widgetGoalsgetItemsCategory + table + 1 + + + Product SKU + + Goals_Ecommerce + Ecommerce + 20 + + + Goals_Products + Products + 10 + + Goals + getItemsSku + 130 + + Goals + getItemsSku + + widgetGoalsgetItemsSku + table + 1 + + + Product Name + + Goals_Ecommerce + Ecommerce + 20 + + + Goals_Products + Products + 10 + + Goals + getItemsName + 131 + + Goals + getItemsName + + widgetGoalsgetItemsName + table + 1 + + + Product Category + + Goals_Ecommerce + Ecommerce + 20 + + + Goals_Products + Products + 10 + + Goals + getItemsCategory + 132 + + Goals + getItemsCategory + + widgetGoalsgetItemsCategory + table + 1 + + + Overview + + Goals_Goals + Goals + 25 + + + General_Overview + Overview + 2 + + CoreHome + renderWidgetContainer + 5 + + CoreHome + renderWidgetContainer + GoalsOverview + + widgetGoalsOverview + + 1 + + + + + Goals_Goals + Goals + 99 + + + General_Overview + Overview + 99 + + Goals + getEvolutionGraph + 1 + + 1 + graphEvolution + Goals + getEvolutionGraph + + widgetGoalsgetEvolutionGraphforceView1viewDataTablegraphEvolution + graphEvolution + 1 + + + + + Goals_Goals + Goals + 99 + + + General_Overview + Overview + 99 + + Goals + get + 2 + + 1 + sparklines + Goals + get + + widgetGoalsgetforceView1viewDataTablesparklines + sparklines + 1 + + + Goal Goal 1 - Thank you + + Goals_Goals + Goals + 99 + + + General_Overview + Overview + 99 + + Goals + get + 3 + + 1 + sparklines + Goals + get + 1 + 1 + 1 + + widgetGoalsgetforceView1viewDataTablesparklinesidGoal1allow_multiple1only_summary1 + sparklines + 1 + + + Goal Goal 2 - Hello + + Goals_Goals + Goals + 99 + + + General_Overview + Overview + 99 + + Goals + get + 4 + + 1 + sparklines + Goals + get + 2 + 0 + 1 + + widgetGoalsgetforceView1viewDataTablesparklinesidGoal2allow_multiple0only_summary1 + sparklines + 1 + + + Goal triggered js + + Goals_Goals + Goals + 99 + + + General_Overview + Overview + 99 + + Goals + get + 5 + + 1 + sparklines + Goals + get + 3 + 0 + 1 + + widgetGoalsgetforceView1viewDataTablesparklinesidGoal3allow_multiple0only_summary1 + sparklines + 1 + + + + + Goal 1 - Thank you + + Goals_Goals + Goals + 25 + + + 1 + Goal 1 - Thank you + 900 + + CoreHome + renderWidgetContainer + 15 + + CoreHome + renderWidgetContainer + Goal_1 + + widgetGoal_1 + + 1 + + + + + Goals_Goals + Goals + 99 + + + 1 + 1 + 99 + + Goals + getEvolutionGraph + 13 + + 1 + graphEvolution + Goals + getEvolutionGraph + 1 + + widgetGoalsgetEvolutionGraphforceView1viewDataTablegraphEvolutionidGoal1 + graphEvolution + 1 + + + + + Goals_Goals + Goals + 99 + + + 1 + 1 + 99 + + Goals + get + 14 + + 1 + sparklines + Goals + get + 1 + 1 + + widgetGoalsgetforceView1viewDataTablesparklinesidGoal1allow_multiple1 + sparklines + 1 + + + Conversions Overview + + Goals_Goals + Goals + 99 + + + 1 + 1 + 99 + + Goals + goalConversionsOverview + 15 + + Goals + goalConversionsOverview + 1 + + widgetGoalsgoalConversionsOverviewidGoal1 + + Goals + hasConversions + 1 + + table + 1 + + + + + Goal 2 - Hello + + Goals_Goals + Goals + 25 + + + 2 + Goal 2 - Hello + 901 + + CoreHome + renderWidgetContainer + 20 + + CoreHome + renderWidgetContainer + Goal_2 + + widgetGoal_2 + + 1 + + + + + Goals_Goals + Goals + 99 + + + 2 + 2 + 99 + + Goals + getEvolutionGraph + 18 + + 1 + graphEvolution + Goals + getEvolutionGraph + 2 + + widgetGoalsgetEvolutionGraphforceView1viewDataTablegraphEvolutionidGoal2 + graphEvolution + 1 + + + + + Goals_Goals + Goals + 99 + + + 2 + 2 + 99 + + Goals + get + 19 + + 1 + sparklines + Goals + get + 2 + 0 + + widgetGoalsgetforceView1viewDataTablesparklinesidGoal2allow_multiple0 + sparklines + 1 + + + Conversions Overview + + Goals_Goals + Goals + 99 + + + 2 + 2 + 99 + + Goals + goalConversionsOverview + 20 + + Goals + goalConversionsOverview + 2 + + widgetGoalsgoalConversionsOverviewidGoal2 + + Goals + hasConversions + 2 + + table + 1 + + + + + triggered js + + Goals_Goals + Goals + 25 + + + 3 + triggered js + 902 + + CoreHome + renderWidgetContainer + 25 + + CoreHome + renderWidgetContainer + Goal_3 + + widgetGoal_3 + + 1 + + + + + Goals_Goals + Goals + 99 + + + 3 + 3 + 99 + + Goals + getEvolutionGraph + 23 + + 1 + graphEvolution + Goals + getEvolutionGraph + 3 + + widgetGoalsgetEvolutionGraphforceView1viewDataTablegraphEvolutionidGoal3 + graphEvolution + 1 + + + + + Goals_Goals + Goals + 99 + + + 3 + 3 + 99 + + Goals + get + 24 + + 1 + sparklines + Goals + get + 3 + 0 + + widgetGoalsgetforceView1viewDataTablesparklinesidGoal3allow_multiple0 + sparklines + 1 + + + Conversions Overview + + Goals_Goals + Goals + 99 + + + 3 + 3 + 99 + + Goals + goalConversionsOverview + 25 + + Goals + goalConversionsOverview + 3 + + widgetGoalsgoalConversionsOverviewidGoal3 + + Goals + hasConversions + 3 + + table + 1 + + + + + Data tables + + ExampleUI_UiFramework + UI Framework + 90 + + + ExampleUI_GetTemperaturesDataTable + Data tables + 99 + + ExampleUI + getTemperatures + 210 + + ExampleUI + getTemperatures + + widgetExampleUIgetTemperatures + table + 1 + + + Data tables + + ExampleUI_UiFramework + UI Framework + 90 + + + Bar graph + Bar graph + 99 + + ExampleUI + getTemperatures + 210 + + 1 + graphVerticalBar + ExampleUI + getTemperatures + + widgetExampleUIgetTemperaturesforceView1viewDataTablegraphVerticalBar + graphVerticalBar + 1 + + + Treemap example + + ExampleUI_UiFramework + UI Framework + 90 + + + Treemap + Treemap + 99 + + ExampleUI + getTemperatures + 210 + + 1 + infoviz-treemap + ExampleUI + getTemperatures + + widgetExampleUIgetTemperaturesforceView1viewDataTableinfoviz-treemap + infoviz-treemap + 1 + + + Evolution of server temperatures over the last few days + + ExampleUI_UiFramework + UI Framework + 90 + + + Evolution Graph + Evolution Graph + 99 + + ExampleUI + getTemperaturesEvolution + 211 + + 1 + graphEvolution + ExampleUI + getTemperaturesEvolution + + server1 + server2 + + + widgetExampleUIgetTemperaturesEvolutionforceView1viewDataTablegraphEvolutioncolumnsArray + graphEvolution + 1 + + + Temperatures evolution over time + + ExampleUI_UiFramework + UI Framework + 90 + + + Sparklines + Sparklines + 99 + + ExampleUI + getTemperaturesEvolution + 211 + + 1 + sparklines + ExampleUI + getTemperaturesEvolution + + widgetExampleUIgetTemperaturesEvolutionforceView1viewDataTablesparklines + sparklines + 1 + + + Advanced tag cloud: with logos and links + + ExampleUI_UiFramework + UI Framework + 90 + + + Tag clouds + Tag clouds + 99 + + ExampleUI + getPlanetRatiosWithLogos + 213 + + cloud + ExampleUI + getPlanetRatiosWithLogos + + widgetExampleUIgetPlanetRatiosWithLogosviewDataTablecloud + cloud + 1 + + + Simple tag cloud + + ExampleUI_UiFramework + UI Framework + 90 + + + Tag clouds + Tag clouds + 99 + + ExampleUI + getPlanetRatios + 5 + + 1 + cloud + ExampleUI + getPlanetRatios + + widgetExampleUIgetPlanetRatiosforceView1viewDataTablecloud + cloud + 1 + + + Pie graph + + ExampleUI_UiFramework + UI Framework + 90 + + + Pie graph + Pie graph + 99 + + ExampleUI + getPlanetRatios + 212 + + graphPie + ExampleUI + getPlanetRatios + + widgetExampleUIgetPlanetRatiosviewDataTablegraphPie + graphPie + 1 + + + Top Keywords for Page URL + + SEO + SEO + 99 + + + Referrers + getKeywordsForPage + 99 + + Referrers + getKeywordsForPage + + widgetReferrersgetKeywordsForPage + + + Movers and Shakers + + Insights_WidgetCategory + Insights + 99 + + + Insights + getOverallMoversAndShakers + 99 + + Insights + getOverallMoversAndShakers + + widgetInsightsgetOverallMoversAndShakers + + + Example Widget Name + + Example Widgets + Example Widgets + 99 + + + ExamplePlugin + myExampleWidget + 99 + + ExamplePlugin + myExampleWidget + + widgetExamplePluginmyExampleWidget + + + Piwik Changelog + + Example Widgets + Example Widgets + 99 + + + ExampleRssWidget + rssChangelog + 99 + + ExampleRssWidget + rssChangelog + + widgetExampleRssWidgetrssChangelog + + + SEO Rankings + + SEO + SEO + 99 + + + SEO + getRank + 99 + + SEO + getRank + + widgetSEOgetRank + + + Insights Overview + + Insights_WidgetCategory + Insights + 99 + + + Insights + getInsightsOverview + 99 + + Insights + getInsightsOverview + + widgetInsightsgetInsightsOverview + + + Welcome! + + Example Widgets + Example Widgets + 99 + + + CoreHome + getPromoVideo + 10 + + CoreHome + getPromoVideo + + widgetCoreHomegetPromoVideo + + + Piwik.org Blog + + Example Widgets + Example Widgets + 99 + + + ExampleRssWidget + rssPiwik + 99 + + ExampleRssWidget + rssPiwik + + widgetExampleRssWidgetrssPiwik + + + Support Piwik! + + Example Widgets + Example Widgets + 99 + + + CoreHome + getDonateForm + 5 + + CoreHome + getDonateForm + + widgetCoreHomegetDonateForm + + \ No newline at end of file diff --git a/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getWidgetMetadata_day.xml b/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getWidgetMetadata_day.xml new file mode 100644 index 0000000000..fa3b20ac00 --- /dev/null +++ b/tests/PHPUnit/System/expected/test_apiGetReportMetadata__API.getWidgetMetadata_day.xml @@ -0,0 +1,1987 @@ + + + + Visitors in Real-time + + Live! + 2 + Live! + + + Live + widget + 20 + + Live + widget + + widgetLivewidget + + + Real Time Visitor Count + + Live! + 2 + Live! + + + Live + getSimpleLastVisitCount + 15 + + Live + getSimpleLastVisitCount + + widgetLivegetSimpleLastVisitCount + table + 1 + + + Visits Over Time + + Visitors + 5 + General_Visitors + + + Overview + 2 + General_Overview + + VisitsSummary + getEvolutionGraph + 5 + + 1 + graphEvolution + VisitsSummary + getEvolutionGraph + + widgetVisitsSummarygetEvolutionGraphforceView1viewDataTablegraphEvolution + graphEvolution + 1 + + + Visitor Log + + Visitors + 5 + General_Visitors + + + Visitor Log + 5 + Live_VisitorLog + + Live + getLastVisitsDetails + 10 + + 1 + Piwik\Plugins\Live\VisitorLog + Live + getLastVisitsDetails + 1 + + widgetLivegetLastVisitsDetailsforceView1viewDataTablePiwik%5CPlugins%5CLive%5CVisitorLogsmall1 + Piwik\Plugins\Live\VisitorLog + 1 + + + Custom Variables + + Visitors + 5 + General_Visitors + + + Custom Variables + 10 + CustomVariables_CustomVariables + + CustomVariables + getCustomVariables + 110 + + CustomVariables + getCustomVariables + + widgetCustomVariablesgetCustomVariables + table + 1 + + + Device model + + Visitors + 5 + General_Visitors + + + Devices + 15 + DevicesDetection_Devices + + DevicesDetection + getModel + 102 + + DevicesDetection + getModel + + widgetDevicesDetectiongetModel + table + 1 + + + Device type + + Visitors + 5 + General_Visitors + + + Devices + 15 + DevicesDetection_Devices + + DevicesDetection + getType + 100 + + DevicesDetection + getType + + widgetDevicesDetectiongetType + table + 1 + + + Screen Resolution + + Visitors + 5 + General_Visitors + + + Devices + 15 + DevicesDetection_Devices + + Resolution + getResolution + 108 + + Resolution + getResolution + + widgetResolutiongetResolution + table + 1 + + + Device brand + + Visitors + 5 + General_Visitors + + + Devices + 15 + DevicesDetection_Devices + + DevicesDetection + getBrand + 104 + + DevicesDetection + getBrand + + widgetDevicesDetectiongetBrand + table + 1 + + + Operating System versions + + Visitors + 5 + General_Visitors + + + Software + 20 + DevicesDetection_Software + + DevicesDetection + getOsVersions + 102 + + DevicesDetection + getOsVersions + + widgetDevicesDetectiongetOsVersions + table + 1 + + + Browsers + + Visitors + 5 + General_Visitors + + + Software + 20 + DevicesDetection_Software + + DevicesDetection + getBrowsers + 105 + + DevicesDetection + getBrowsers + + widgetDevicesDetectiongetBrowsers + table + 1 + + + Visits Overview (with graph) + + Visitors + 5 + General_Visitors + + + CoreHome + renderWidgetContainer + 99 + + CoreHome + renderWidgetContainer + VisitOverviewWithGraph + + widgetVisitOverviewWithGraph + + 1 + + + Visits Overview + + Visitors + 5 + General_Visitors + + + Overview + 2 + General_Overview + + VisitsSummary + get + 10 + + 1 + sparklines + VisitsSummary + get + + widgetVisitsSummarygetforceView1viewDataTablesparklines + sparklines + 1 + + + Browser version + + Visitors + 5 + General_Visitors + + + Software + 20 + DevicesDetection_Software + + DevicesDetection + getBrowserVersions + 106 + + DevicesDetection + getBrowserVersions + + widgetDevicesDetectiongetBrowserVersions + table + 1 + + + Configurations + + Visitors + 5 + General_Visitors + + + Software + 20 + DevicesDetection_Software + + Resolution + getConfiguration + 107 + + Resolution + getConfiguration + + widgetResolutiongetConfiguration + table + 1 + + + Browser Plugins + + Visitors + 5 + General_Visitors + + + Software + 20 + DevicesDetection_Software + + DevicePlugins + getPlugin + 113 + + DevicePlugins + getPlugin + + widgetDevicePluginsgetPlugin + table + 1 + + + Browser engines + + Visitors + 5 + General_Visitors + + + Software + 20 + DevicesDetection_Software + + DevicesDetection + getBrowserEngines + 110 + + graphPie + DevicesDetection + getBrowserEngines + + widgetDevicesDetectiongetBrowserEnginesviewDataTablegraphPie + graphPie + 1 + + + Operating System families + + Visitors + 5 + General_Visitors + + + Software + 20 + DevicesDetection_Software + + DevicesDetection + getOsFamilies + 108 + + DevicesDetection + getOsFamilies + + widgetDevicesDetectiongetOsFamilies + table + 1 + + + Browser language + + Visitors + 5 + General_Visitors + + + Locations + 25 + UserCountry_SubmenuLocations + + UserLanguage + getLanguage + 108 + + UserLanguage + getLanguage + + widgetUserLanguagegetLanguage + table + 1 + + + Region + + Visitors + 5 + General_Visitors + + + Locations + 25 + UserCountry_SubmenuLocations + + UserCountry + getRegion + 107 + + UserCountry + getRegion + + widgetUserCountrygetRegion + table + 1 + + + Country + + Visitors + 5 + General_Visitors + + + Locations + 25 + UserCountry_SubmenuLocations + + UserCountry + getCountry + 105 + + UserCountry + getCountry + + widgetUserCountrygetCountry + table + 1 + + + Language code + + Visitors + 5 + General_Visitors + + + Locations + 25 + UserCountry_SubmenuLocations + + UserLanguage + getLanguageCode + 111 + + UserLanguage + getLanguageCode + + widgetUserLanguagegetLanguageCode + table + 1 + + + Continent + + Visitors + 5 + General_Visitors + + + Locations + 25 + UserCountry_SubmenuLocations + + UserCountry + getContinent + 106 + + UserCountry + getContinent + + widgetUserCountrygetContinent + table + 1 + + + Visitor profile + + Visitors + 5 + General_Visitors + + + Live + getVisitorProfilePopup + 25 + + Live + getVisitorProfilePopup + + widgetLivegetVisitorProfilePopup + + + Providers + + Visitors + 5 + General_Visitors + + + Locations + 25 + UserCountry_SubmenuLocations + + Provider + getProvider + 150 + + Provider + getProvider + + widgetProvidergetProvider + table + 1 + + + City + + Visitors + 5 + General_Visitors + + + Locations + 25 + UserCountry_SubmenuLocations + + UserCountry + getCity + 110 + + UserCountry + getCity + + widgetUserCountrygetCity + table + 1 + + + Visitor Map + + Visitors + 5 + General_Visitors + + + Locations + 25 + UserCountry_SubmenuLocations + + UserCountryMap + visitorMap + 1 + + UserCountryMap + visitorMap + + widgetUserCountryMapvisitorMap + + + Visits per visit duration + + Visitors + 5 + General_Visitors + + + Engagement + 30 + VisitorInterest_Engagement + + VisitorInterest + getNumberOfVisitsPerVisitDuration + 115 + + cloud + VisitorInterest + getNumberOfVisitsPerVisitDuration + + widgetVisitorInterestgetNumberOfVisitsPerVisitDurationviewDataTablecloud + cloud + 1 + + + Returning Visits Over Time + + Visitors + 5 + General_Visitors + + + Engagement + 30 + VisitorInterest_Engagement + + VisitFrequency + getEvolutionGraph + 1 + + 1 + graphEvolution + VisitFrequency + getEvolutionGraph + + widgetVisitFrequencygetEvolutionGraphforceView1viewDataTablegraphEvolution + graphEvolution + 1 + + + Visits by Days Since Last Visit + + Visitors + 5 + General_Visitors + + + Engagement + 30 + VisitorInterest_Engagement + + VisitorInterest + getNumberOfVisitsByDaysSinceLast + 130 + + VisitorInterest + getNumberOfVisitsByDaysSinceLast + + widgetVisitorInterestgetNumberOfVisitsByDaysSinceLast + table + 1 + + + Visits by Visit Number + + Visitors + 5 + General_Visitors + + + Engagement + 30 + VisitorInterest_Engagement + + VisitorInterest + getNumberOfVisitsByVisitCount + 125 + + VisitorInterest + getNumberOfVisitsByVisitCount + + widgetVisitorInterestgetNumberOfVisitsByVisitCount + table + 1 + + + Visits per number of pages + + Visitors + 5 + General_Visitors + + + Engagement + 30 + VisitorInterest_Engagement + + VisitorInterest + getNumberOfVisitsPerPage + 120 + + cloud + VisitorInterest + getNumberOfVisitsPerPage + + widgetVisitorInterestgetNumberOfVisitsPerPageviewDataTablecloud + cloud + 1 + + + Frequency Overview + + Visitors + 5 + General_Visitors + + + Engagement + 30 + VisitorInterest_Engagement + + VisitFrequency + get + 2 + + 1 + sparklines + VisitFrequency + get + + widgetVisitFrequencygetforceView1viewDataTablesparklines + sparklines + 1 + + + Visits per server time + + Visitors + 5 + General_Visitors + + + Times + 35 + VisitTime_SubmenuTimes + + VisitTime + getVisitInformationPerServerTime + 120 + + graphVerticalBar + VisitTime + getVisitInformationPerServerTime + + widgetVisitTimegetVisitInformationPerServerTimeviewDataTablegraphVerticalBar + graphVerticalBar + 1 + + + Visits per local time + + Visitors + 5 + General_Visitors + + + Times + 35 + VisitTime_SubmenuTimes + + VisitTime + getVisitInformationPerLocalTime + 115 + + graphVerticalBar + VisitTime + getVisitInformationPerLocalTime + + widgetVisitTimegetVisitInformationPerLocalTimeviewDataTablegraphVerticalBar + graphVerticalBar + 1 + + + Visits by Day of Week + + Visitors + 5 + General_Visitors + + + Times + 35 + VisitTime_SubmenuTimes + + VisitTime + getByDayOfWeek + 125 + + graphVerticalBar + VisitTime + getByDayOfWeek + + widgetVisitTimegetByDayOfWeekviewDataTablegraphVerticalBar + graphVerticalBar + 1 + + + Real-time Map + + Visitors + 5 + General_Visitors + + + Real-time Map + 40 + UserCountryMap_RealTimeMap + + UserCountryMap + realtimeMap + 5 + + UserCountryMap + realtimeMap + + widgetUserCountryMaprealtimeMap + + + Pages + + Actions + 10 + General_Actions + + + Pages + 5 + General_Pages + + Actions + getPageUrls + 102 + + Actions + getPageUrls + + widgetActionsgetPageUrls + table + 1 + + + Entry pages + + Actions + 10 + General_Actions + + + Entry pages + 10 + Actions_SubmenuPagesEntry + + Actions + getEntryPageUrls + 103 + + Actions + getEntryPageUrls + + widgetActionsgetEntryPageUrls + table + 1 + + + Exit pages + + Actions + 10 + General_Actions + + + Exit pages + 15 + Actions_SubmenuPagesExit + + Actions + getExitPageUrls + 104 + + Actions + getExitPageUrls + + widgetActionsgetExitPageUrls + table + 1 + + + Page titles + + Actions + 10 + General_Actions + + + Page titles + 20 + Actions_SubmenuPageTitles + + Actions + getPageTitles + 105 + + Actions + getPageTitles + + widgetActionsgetPageTitles + table + 1 + + + Site Search Keywords + + Actions + 10 + General_Actions + + + Site Search + 25 + Actions_SubmenuSitesearch + + Actions + getSiteSearchKeywords + 115 + + Actions + getSiteSearchKeywords + + widgetActionsgetSiteSearchKeywords + table + 1 + + + Search Keywords with No Results + + Actions + 10 + General_Actions + + + Site Search + 25 + Actions_SubmenuSitesearch + + Actions + getSiteSearchNoResultKeywords + 118 + + Actions + getSiteSearchNoResultKeywords + + widgetActionsgetSiteSearchNoResultKeywords + table + 1 + + + Page Titles Following a Site Search + + Actions + 10 + General_Actions + + + Site Search + 25 + Actions_SubmenuSitesearch + + Actions + getPageTitlesFollowingSiteSearch + 119 + + Actions + getPageTitlesFollowingSiteSearch + + widgetActionsgetPageTitlesFollowingSiteSearch + table + 1 + + + Pages Following a Site Search + + Actions + 10 + General_Actions + + + Site Search + 25 + Actions_SubmenuSitesearch + + Actions + getPageUrlsFollowingSiteSearch + 116 + + Actions + getPageUrlsFollowingSiteSearch + + widgetActionsgetPageUrlsFollowingSiteSearch + table + 1 + + + Search Categories + + Actions + 10 + General_Actions + + + Site Search + 25 + Actions_SubmenuSitesearch + + Actions + getSiteSearchCategories + 120 + + Actions + getSiteSearchCategories + + widgetActionsgetSiteSearchCategories + table + 1 + + + Entry Page Titles + + Actions + 10 + General_Actions + + + Actions + getEntryPageTitles + 106 + + Actions + getEntryPageTitles + + widgetActionsgetEntryPageTitles + table + 1 + + + Exit page titles + + Actions + 10 + General_Actions + + + Actions + getExitPageTitles + 107 + + Actions + getExitPageTitles + + widgetActionsgetExitPageTitles + table + 1 + + + Outlinks + + Actions + 10 + General_Actions + + + Outlinks + 30 + General_Outlinks + + Actions + getOutlinks + 108 + + Actions + getOutlinks + + widgetActionsgetOutlinks + table + 1 + + + Downloads + + Actions + 10 + General_Actions + + + Downloads + 35 + General_Downloads + + Actions + getDownloads + 109 + + Actions + getDownloads + + widgetActionsgetDownloads + table + 1 + + + Event Names + + Actions + 10 + General_Actions + + + Events + 40 + Events_Events + + Events + getName + 102 + + Events + getName + eventAction + + widgetEventsgetNamesecondaryDimensioneventAction + table + 1 + + + Event Categories + + Actions + 10 + General_Actions + + + Events + 40 + Events_Events + + Events + getCategory + 100 + + Events + getCategory + eventAction + + widgetEventsgetCategorysecondaryDimensioneventAction + table + 1 + + + Event Actions + + Actions + 10 + General_Actions + + + Events + 40 + Events_Events + + Events + getAction + 101 + + Events + getAction + eventName + + widgetEventsgetActionsecondaryDimensioneventName + table + 1 + + + Content Name + + Actions + 10 + General_Actions + + + Contents + 45 + Contents_Contents + + Contents + getContentNames + 135 + + Contents + getContentNames + + widgetContentsgetContentNames + table + 1 + + + Content Piece + + Actions + 10 + General_Actions + + + Contents + 45 + Contents_Contents + + Contents + getContentPieces + 136 + + Contents + getContentPieces + + widgetContentsgetContentPieces + table + 1 + + + Referrer Types + + Referrers + 15 + Referrers_Referrers + + + All Referrers + 5 + Referrers_WidgetGetAll + + Referrers + getReferrerType + 101 + + tableAllColumns + Referrers + getReferrerType + + widgetReferrersgetReferrerTypeviewDataTabletableAllColumns + tableAllColumns + 1 + + + Referrers + + Referrers + 15 + Referrers_Referrers + + + All Referrers + 5 + Referrers_WidgetGetAll + + Referrers + getAll + 102 + + tableAllColumns + Referrers + getAll + + widgetReferrersgetAllviewDataTabletableAllColumns + tableAllColumns + 1 + + + Search Engines + + Referrers + 15 + Referrers_Referrers + + + Search Engines & Keywords + 10 + Referrers_SubmenuSearchEngines + + Referrers + getSearchEngines + 107 + + Referrers + getSearchEngines + + widgetReferrersgetSearchEngines + table + 1 + + + Keywords + + Referrers + 15 + Referrers_Referrers + + + Search Engines & Keywords + 10 + Referrers_SubmenuSearchEngines + + Referrers + getKeywords + 103 + + Referrers + getKeywords + + widgetReferrersgetKeywords + table + 1 + + + Social Networks + + Referrers + 15 + Referrers_Referrers + + + Websites & Social + 15 + Referrers_SubmenuWebsites + + Referrers + getSocials + 111 + + graphPie + Referrers + getSocials + + widgetReferrersgetSocialsviewDataTablegraphPie + graphPie + 1 + + + Websites + + Referrers + 15 + Referrers_Referrers + + + Websites & Social + 15 + Referrers_SubmenuWebsites + + Referrers + getWebsites + 105 + + Referrers + getWebsites + + widgetReferrersgetWebsites + table + 1 + + + Campaigns + + Referrers + 15 + Referrers_Referrers + + + Campaigns + 20 + Referrers_Campaigns + + Referrers + getCampaigns + 109 + + Referrers + getCampaigns + + widgetReferrersgetCampaigns + table + 1 + + + Overview + + Ecommerce + 20 + Goals_Ecommerce + + + Overview + 2 + General_Overview + + CoreHome + renderWidgetContainer + 9 + + CoreHome + renderWidgetContainer + EcommerceOverview + + widgetEcommerceOverview + + 1 + + + Ecommerce Log + + Ecommerce + 20 + Goals_Ecommerce + + + Ecommerce Log + 5 + Goals_EcommerceLog + + Ecommerce + getEcommerceLog + 99 + + Ecommerce + getEcommerceLog + + widgetEcommercegetEcommerceLog + + + Product Name + + Ecommerce + 20 + Goals_Ecommerce + + + Products + 10 + Goals_Products + + Goals + getItemsName + 131 + + Goals + getItemsName + 1 + + widgetGoalsgetItemsNameabandonedCarts1 + table + 1 + + + Product Category + + Ecommerce + 20 + Goals_Ecommerce + + + Products + 10 + Goals_Products + + Goals + getItemsCategory + 132 + + Goals + getItemsCategory + 1 + + widgetGoalsgetItemsCategoryabandonedCarts1 + table + 1 + + + Product SKU + + Ecommerce + 20 + Goals_Ecommerce + + + Products + 10 + Goals_Products + + Goals + getItemsSku + 130 + + Goals + getItemsSku + 1 + + widgetGoalsgetItemsSkuabandonedCarts1 + table + 1 + + + Overview + + Goals + 25 + Goals_Goals + + + Overview + 2 + General_Overview + + CoreHome + renderWidgetContainer + 6 + + CoreHome + renderWidgetContainer + GoalsOverview + + widgetGoalsOverview + + 1 + + + Goal 1 - Thank you + + Goals + 25 + Goals_Goals + + + Goal 1 - Thank you + 900 + 1 + + CoreHome + renderWidgetContainer + 13 + + CoreHome + renderWidgetContainer + Goal_1 + + widgetGoal_1 + + 1 + + + Goal 2 - Hello + + Goals + 25 + Goals_Goals + + + Goal 2 - Hello + 901 + 2 + + CoreHome + renderWidgetContainer + 17 + + CoreHome + renderWidgetContainer + Goal_2 + + widgetGoal_2 + + 1 + + + triggered js + + Goals + 25 + Goals_Goals + + + triggered js + 902 + 3 + + CoreHome + renderWidgetContainer + 22 + + CoreHome + renderWidgetContainer + Goal_3 + + widgetGoal_3 + + 1 + + + Data tables + + UI Framework + 90 + ExampleUI_UiFramework + + + Data tables + 99 + ExampleUI_GetTemperaturesDataTable + + ExampleUI + getTemperatures + 210 + + ExampleUI + getTemperatures + + widgetExampleUIgetTemperatures + table + 1 + + + Data tables + + UI Framework + 90 + ExampleUI_UiFramework + + + Bar graph + 99 + Bar graph + + ExampleUI + getTemperatures + 210 + + 1 + graphVerticalBar + ExampleUI + getTemperatures + + widgetExampleUIgetTemperaturesforceView1viewDataTablegraphVerticalBar + graphVerticalBar + 1 + + + Temperatures evolution over time + + UI Framework + 90 + ExampleUI_UiFramework + + + Sparklines + 99 + Sparklines + + ExampleUI + getTemperaturesEvolution + 211 + + 1 + sparklines + ExampleUI + getTemperaturesEvolution + + widgetExampleUIgetTemperaturesEvolutionforceView1viewDataTablesparklines + sparklines + 1 + + + Treemap example + + UI Framework + 90 + ExampleUI_UiFramework + + + Treemap + 99 + Treemap + + ExampleUI + getTemperatures + 210 + + 1 + infoviz-treemap + ExampleUI + getTemperatures + + widgetExampleUIgetTemperaturesforceView1viewDataTableinfoviz-treemap + infoviz-treemap + 1 + + + Simple tag cloud + + UI Framework + 90 + ExampleUI_UiFramework + + + Tag clouds + 99 + Tag clouds + + ExampleUI + getPlanetRatios + 5 + + 1 + cloud + ExampleUI + getPlanetRatios + + widgetExampleUIgetPlanetRatiosforceView1viewDataTablecloud + cloud + 1 + + + Advanced tag cloud: with logos and links + + UI Framework + 90 + ExampleUI_UiFramework + + + Tag clouds + 99 + Tag clouds + + ExampleUI + getPlanetRatiosWithLogos + 213 + + cloud + ExampleUI + getPlanetRatiosWithLogos + + widgetExampleUIgetPlanetRatiosWithLogosviewDataTablecloud + cloud + 1 + + + Evolution of server temperatures over the last few days + + UI Framework + 90 + ExampleUI_UiFramework + + + Evolution Graph + 99 + Evolution Graph + + ExampleUI + getTemperaturesEvolution + 211 + + 1 + graphEvolution + ExampleUI + getTemperaturesEvolution + + server1 + server2 + + + widgetExampleUIgetTemperaturesEvolutionforceView1viewDataTablegraphEvolutioncolumnsArray + graphEvolution + 1 + + + Pie graph + + UI Framework + 90 + ExampleUI_UiFramework + + + Pie graph + 99 + Pie graph + + ExampleUI + getPlanetRatios + 212 + + graphPie + ExampleUI + getPlanetRatios + + widgetExampleUIgetPlanetRatiosviewDataTablegraphPie + graphPie + 1 + + + Insights Overview + + Insights + 99 + Insights_WidgetCategory + + + Insights + getInsightsOverview + 99 + + Insights + getInsightsOverview + + widgetInsightsgetInsightsOverview + + + Top Keywords for Page URL + + SEO + 99 + SEO + + + Referrers + getKeywordsForPage + 99 + + Referrers + getKeywordsForPage + + widgetReferrersgetKeywordsForPage + + + Piwik Changelog + + Example Widgets + 99 + Example Widgets + + + ExampleRssWidget + rssChangelog + 99 + + ExampleRssWidget + rssChangelog + + widgetExampleRssWidgetrssChangelog + + + Movers and Shakers + + Insights + 99 + Insights_WidgetCategory + + + Insights + getOverallMoversAndShakers + 99 + + Insights + getOverallMoversAndShakers + + widgetInsightsgetOverallMoversAndShakers + + + Example Widget Name + + Example Widgets + 99 + Example Widgets + + + ExamplePlugin + myExampleWidget + 99 + + ExamplePlugin + myExampleWidget + + widgetExamplePluginmyExampleWidget + + + SEO Rankings + + SEO + 99 + SEO + + + SEO + getRank + 99 + + SEO + getRank + + widgetSEOgetRank + + + Piwik.org Blog + + Example Widgets + 99 + Example Widgets + + + ExampleRssWidget + rssPiwik + 99 + + ExampleRssWidget + rssPiwik + + widgetExampleRssWidgetrssPiwik + + + Welcome! + + Example Widgets + 99 + Example Widgets + + + CoreHome + getPromoVideo + 10 + + CoreHome + getPromoVideo + + widgetCoreHomegetPromoVideo + + + Support Piwik! + + Example Widgets + 99 + Example Widgets + + + CoreHome + getDonateForm + 5 + + CoreHome + getDonateForm + + widgetCoreHomegetDonateForm + + \ No newline at end of file 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 75bcc851e2..4c151f8402 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 @@ -4,6 +4,7 @@ Sunday 4 January 2009 Visitors + Locations Country UserCountry getCountry 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 4dc81bddda..775bc1b478 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 @@ -4,6 +4,7 @@ 2009 Visiteurs + Provenances géographiques Pays UserCountry getCountry diff --git a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_Metadata_ItemsCategory__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_Metadata_ItemsCategory__API.getProcessedReport_day.xml index 70117fb4d3..f9cc082667 100644 --- a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_Metadata_ItemsCategory__API.getProcessedReport_day.xml +++ b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_Metadata_ItemsCategory__API.getProcessedReport_day.xml @@ -4,6 +4,7 @@ Tuesday 5 April 2011 Ecommerce + Products Product Category Goals getItemsCategory diff --git a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_Metadata_ItemsSku__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_Metadata_ItemsSku__API.getProcessedReport_day.xml index 20079eb4c4..280eb66c76 100644 --- a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_Metadata_ItemsSku__API.getProcessedReport_day.xml +++ b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_Metadata_ItemsSku__API.getProcessedReport_day.xml @@ -4,6 +4,7 @@ Tuesday 5 April 2011 Ecommerce + Products Product SKU Goals getItemsSku diff --git a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_Metadata_VisitTime.getVisitInformationPerServerTime__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_Metadata_VisitTime.getVisitInformationPerServerTime__API.getProcessedReport_day.xml index a0a7bbea54..2198b397f4 100755 --- a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_Metadata_VisitTime.getVisitInformationPerServerTime__API.getProcessedReport_day.xml +++ b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_Metadata_VisitTime.getVisitInformationPerServerTime__API.getProcessedReport_day.xml @@ -3,8 +3,9 @@ Piwik test Tuesday 5 April 2011 - Visits Summary - Visits by Server Time + Visitors + Times + Visits per server time VisitTime getVisitInformationPerServerTime Server time diff --git a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems__API.getProcessedReport_day.xml b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems__API.getProcessedReport_day.xml index 3d36e8c075..47a58e7e28 100755 --- a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems__API.getProcessedReport_day.xml +++ b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems__API.getProcessedReport_day.xml @@ -4,6 +4,7 @@ Tuesday 5 April 2011 Visitors + Locations Country UserCountry getCountry diff --git a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_scheduled_report_in_csv__ScheduledReports.generateReport_week.original.csv b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_scheduled_report_in_csv__ScheduledReports.generateReport_week.original.csv index f874d6dd9a..eb2116b7ed 100644 --- a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_scheduled_report_in_csv__ScheduledReports.generateReport_week.original.csv +++ b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_scheduled_report_in_csv__ScheduledReports.generateReport_week.original.csv @@ -493,4 +493,3 @@ Windows XP,5,16,80%,3.2,00:22:49,20% Browser engines label,nb_visits,nb_actions,conversion_rate,nb_actions_per_visit,avg_time_on_site,bounce_rate Gecko (Firefox),5,16,80%,3.2,00:22:49,20% - diff --git a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_scheduled_report_in_html_tables_only__ScheduledReports.generateReport_week.original.html b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_scheduled_report_in_html_tables_only__ScheduledReports.generateReport_week.original.html index b34c15199f..4a378e8a36 100644 --- a/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_scheduled_report_in_html_tables_only__ScheduledReports.generateReport_week.original.html +++ b/tests/PHPUnit/System/expected/test_ecommerceOrderWithItems_scheduled_report_in_html_tables_only__ScheduledReports.generateReport_week.original.html @@ -16,6535 +16,6602 @@

    -

    - Report list -

    - +

    + Report list +

    +

    All Websites dashboard

    - - -
    +  Name   + +  Value   +
    - Gecko (Firefox) - 2 - - 2 - - 1 - - 00:00:00 - - 100% + 0
    + Visits with Conversions - 0% + 0
    - Presto (Opera) - 1 - - 1 - - 1 - - 00:00:00 - - 100% + $ 0
    + Conversion Rate 0%
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Website   - -  Visits   - -  Actions   - -  Pageviews   - -  Revenue   - -  Conversions   - -  Ecommerce Orders   - -  Product Revenue   -
    - Piwik test - 5 - - 16 - - 16 - - $ 13361.11 - - 5 - - 4 - - $ 13351.11 -
    - Piwik test - 2 - - 1 - - 1 - - $ 250 - - 1 - - 0 - - $ 0 -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Website   + +  Visits   + +  Actions   + +  Pageviews   + +  Revenue   + +  Conversions   + +  Ecommerce Orders   + +  Product Revenue   +
    + Piwik test + 5 + + 16 + + 16 + + $ 13361.11 + + 5 + + 4 + + $ 13351.11 +
    + Piwik test + 2 + + 1 + + 1 + + $ 250 + + 1 + + 0 + + $ 0 +
    +
    + + Back to top +

    Visits Summary

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Name   - -  Value   -
    - Unique visitors - 1 -
    - Visits - 5 -
    - Actions - 16 -
    - Maximum actions in one visit - 6 -
    - Actions per Visit - 3.2 -
    - Avg. Visit Duration (in seconds) - 00:22:49 -
    - Bounce Rate - 20% -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Name   + +  Value   +
    + Unique visitors + 1 +
    + Visits + 5 +
    + Actions + 16 +
    + Maximum actions in one visit + 6 +
    + Actions per Visit + 3.2 +
    + Avg. Visit Duration (in seconds) + 00:22:49 +
    + Bounce Rate + 20% +
    +
    + + Back to top +

    Visits by Server Time

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Server time   - -  Visits   - -  Actions   - -  Actions per Visit   - -  Avg. Time on Website   - -  Bounce Rate   - -  Revenue   -
    - 0h - 1 - - 4 - - 4 - - 00:12:01 - - 0% - - $ 10 -
    - 1h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - $ 0 -
    - 2h - 2 - - 9 - - 4.5 - - 00:42:01 - - 0% - - $ 3111.11 -
    - 3h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - $ 0 -
    - 4h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - $ 0 -
    - 5h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - $ 0 -
    - 6h - 1 - - 0 - - 0 - - 00:06:03 - - 100% - - $ 10240 -
    - 7h - 1 - - 3 - - 3 - - 00:12:01 - - 0% - - $ 0 -
    - 8h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - $ 0 -
    - 9h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - $ 0 -
    - 10h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - $ 0 -
    - 11h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - $ 0 -
    - 12h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - $ 0 -
    - 13h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - $ 0 -
    - 14h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - $ 0 -
    - 15h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - $ 0 -
    - 16h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - $ 0 -
    - 17h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - $ 0 -
    - 18h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - $ 0 -
    - 19h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - $ 0 -
    - 20h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - $ 0 -
    - 21h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - $ 0 -
    - 22h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - $ 0 -
    - 23h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - $ 0 -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Server time   + +  Visits   + +  Actions   + +  Actions per Visit   + +  Avg. Time on Website   + +  Bounce Rate   + +  Revenue   +
    + 0h + 1 + + 4 + + 4 + + 00:12:01 + + 0% + + $ 10 +
    + 1h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + $ 0 +
    + 2h + 2 + + 9 + + 4.5 + + 00:42:01 + + 0% + + $ 3111.11 +
    + 3h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + $ 0 +
    + 4h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + $ 0 +
    + 5h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + $ 0 +
    + 6h + 1 + + 0 + + 0 + + 00:06:03 + + 100% + + $ 10240 +
    + 7h + 1 + + 3 + + 3 + + 00:12:01 + + 0% + + $ 0 +
    + 8h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + $ 0 +
    + 9h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + $ 0 +
    + 10h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + $ 0 +
    + 11h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + $ 0 +
    + 12h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + $ 0 +
    + 13h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + $ 0 +
    + 14h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + $ 0 +
    + 15h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + $ 0 +
    + 16h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + $ 0 +
    + 17h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + $ 0 +
    + 18h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + $ 0 +
    + 19h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + $ 0 +
    + 20h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + $ 0 +
    + 21h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + $ 0 +
    + 22h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + $ 0 +
    + 23h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + $ 0 +
    +
    + + Back to top +

    Visits by Local Time

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Local time   - -  Visits   - -  Actions   - -  Actions per Visit   - -  Avg. Time on Website   - -  Bounce Rate   - -  Conversion Rate   -
    - 0h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - 0% -
    - 1h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - 0% -
    - 2h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - 0% -
    - 3h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - 0% -
    - 4h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - 0% -
    - 5h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - 0% -
    - 6h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - 0% -
    - 7h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - 0% -
    - 8h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - 0% -
    - 9h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - 0% -
    - 10h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - 0% -
    - 11h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - 0% -
    - 12h - 5 - - 16 - - 3.2 - - 00:22:49 - - 20% - - 80% -
    - 13h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - 0% -
    - 14h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - 0% -
    - 15h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - 0% -
    - 16h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - 0% -
    - 17h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - 0% -
    - 18h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - 0% -
    - 19h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - 0% -
    - 20h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - 0% -
    - 21h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - 0% -
    - 22h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - 0% -
    - 23h - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - 0% -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Local time   + +  Visits   + +  Actions   + +  Actions per Visit   + +  Avg. Time on Website   + +  Bounce Rate   + +  Conversion Rate   +
    + 0h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + 0% +
    + 1h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + 0% +
    + 2h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + 0% +
    + 3h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + 0% +
    + 4h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + 0% +
    + 5h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + 0% +
    + 6h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + 0% +
    + 7h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + 0% +
    + 8h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + 0% +
    + 9h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + 0% +
    + 10h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + 0% +
    + 11h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + 0% +
    + 12h + 5 + + 16 + + 3.2 + + 00:22:49 + + 20% + + 80% +
    + 13h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + 0% +
    + 14h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + 0% +
    + 15h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + 0% +
    + 16h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + 0% +
    + 17h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + 0% +
    + 18h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + 0% +
    + 19h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + 0% +
    + 20h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + 0% +
    + 21h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + 0% +
    + 22h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + 0% +
    + 23h + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + 0% +
    +
    + + Back to top +

    Visits by Day of Week

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Day of the week   - -  Visits   - -  Actions   - -  Actions per Visit   - -  Avg. Time on Website   - -  Bounce Rate   - -  Conversion Rate   -
    - Monday - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - 0% -
    - Tuesday - 3 - - 13 - - 4.3 - - 00:30:01 - - 0% - - 66.67% -
    - Wednesday - 2 - - 3 - - 1.5 - - 00:12:02 - - 50% - - 100% -
    - Thursday - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - 0% -
    - Friday - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - 0% -
    - Saturday - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - 0% -
    - Sunday - 0 - - 0 - - 0 - - 00:00:00 - - 0% - - 0% -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Day of the week   + +  Visits   + +  Actions   + +  Actions per Visit   + +  Avg. Time on Website   + +  Bounce Rate   + +  Conversion Rate   +
    + Monday + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + 0% +
    + Tuesday + 3 + + 13 + + 4.3 + + 00:30:01 + + 0% + + 66.67% +
    + Wednesday + 2 + + 3 + + 1.5 + + 00:12:02 + + 50% + + 100% +
    + Thursday + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + 0% +
    + Friday + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + 0% +
    + Saturday + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + 0% +
    + Sunday + 0 + + 0 + + 0 + + 00:00:00 + + 0% + + 0% +
    +
    + + Back to top +

    Screen Resolution

    - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Resolution   - -  Visits   - -  Actions   - -  Actions per Visit   - -  Avg. Time on Website   - -  Bounce Rate   - -  Conversion Rate   -
    - 1024x768 - 5 - - 16 - - 3.2 - - 00:22:49 - - 20% - - 80% -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Resolution   + +  Visits   + +  Actions   + +  Actions per Visit   + +  Avg. Time on Website   + +  Bounce Rate   + +  Conversion Rate   +
    + 1024x768 + 5 + + 16 + + 3.2 + + 00:22:49 + + 20% + + 80% +
    +
    + + Back to top +

    Browser Plugins

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Plugin   - -  Visits   - -  % Visits   -
    - -   - Cookie - 5 - - 100% -
    - -   - Flash - 5 - - 100% -
    - -   - Java - 5 - - 100% -
    - -   - Director - 0 - - 0% -
    - -   - Gears - 0 - - 0% -
    - -   - Pdf - 0 - - 0% -
    - -   - Quicktime - 0 - - 0% -
    - -   - Realplayer - 0 - - 0% -
    - -   - Silverlight - 0 - - 0% -
    - -   - Windowsmedia - 0 - - 0% -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Plugin   + +  Visits   + +  % Visits   +
    + +   + Cookie + 5 + + 100% +
    + +   + Flash + 5 + + 100% +
    + +   + Java + 5 + + 100% +
    + +   + Director + 0 + + 0% +
    + +   + Gears + 0 + + 0% +
    + +   + Pdf + 0 + + 0% +
    + +   + Quicktime + 0 + + 0% +
    + +   + Realplayer + 0 + + 0% +
    + +   + Silverlight + 0 + + 0% +
    + +   + Windowsmedia + 0 + + 0% +
    +
    + + Back to top +

    Visitor Configuration

    - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Configuration   - -  Visits   - -  Actions   - -  Actions per Visit   - -  Avg. Time on Website   - -  Bounce Rate   - -  Conversion Rate   -
    - Windows / Firefox / 1024x768 - 5 - - 16 - - 3.2 - - 00:22:49 - - 20% - - 80% -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Configuration   + +  Visits   + +  Actions   + +  Actions per Visit   + +  Avg. Time on Website   + +  Bounce Rate   + +  Conversion Rate   +
    + Windows / Firefox / 1024x768 + 5 + + 16 + + 3.2 + + 00:22:49 + + 20% + + 80% +
    +
    + + Back to top +

    Browser language

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Language   - -  Visits   - -  Actions   - -  Actions per Visit   - -  Avg. Time on Website   - -  Bounce Rate   - -  Conversion Rate   -
    - Polish - 4 - - 12 - - 3 - - 00:25:32 - - 25% - - 75% -
    - French - 1 - - 4 - - 4 - - 00:12:01 - - 0% - - 100% -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Language   + +  Visits   + +  Actions   + +  Actions per Visit   + +  Avg. Time on Website   + +  Bounce Rate   + +  Conversion Rate   +
    + Polish + 4 + + 12 + + 3 + + 00:25:32 + + 25% + + 75% +
    + French + 1 + + 4 + + 4 + + 00:12:01 + + 0% + + 100% +
    +
    + + Back to top +

    Language code

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Language   - -  Visits   - -  Actions   - -  Actions per Visit   - -  Avg. Time on Website   - -  Bounce Rate   - -  Conversion Rate   -
    - Polish (pl) - 4 - - 12 - - 3 - - 00:25:32 - - 25% - - 75% -
    - French (fr) - 1 - - 4 - - 4 - - 00:12:01 - - 0% - - 100% -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Language   + +  Visits   + +  Actions   + +  Actions per Visit   + +  Avg. Time on Website   + +  Bounce Rate   + +  Conversion Rate   +
    + Polish (pl) + 4 + + 12 + + 3 + + 00:25:32 + + 25% + + 75% +
    + French (fr) + 1 + + 4 + + 4 + + 00:12:01 + + 0% + + 100% +
    +
    + + Back to top +

    Ecommerce Orders

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Name   - -  Value   -
    - Ecommerce Orders - 4 -
    - Visits with Conversions - 2 -
    - Revenue - $ 13351.11 -
    - Subtotal - $ 2700 -
    - Tax - $ 531 -
    - Shipping - $ 120.11 -
    - Discount - $ 686 -
    - Purchased Products - 12 -
    - Average Order Value - $ 3337.78 -
    - Conversion Rate - 40% -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Name   + +  Value   +
    + Ecommerce Orders + 4 +
    + Visits with Conversions + 2 +
    + Revenue + $ 13351.11 +
    + Subtotal + $ 2700 +
    + Tax + $ 531 +
    + Shipping + $ 120.11 +
    + Discount + $ 686 +
    + Purchased Products + 12 +
    + Average Order Value + $ 3337.78 +
    + Conversion Rate + 40% +
    +
    + + Back to top +

    Ecommerce Orders - Visits to Conversion

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Visits to Conversion   - -  Conversions   -
    - 1 visit - 2 -
    - 2 visits - 2 -
    - 3 visits - 0 -
    - 4 visits - 0 -
    - 5 visits - 0 -
    - 6 visits - 0 -
    - 7 visits - 0 -
    - 8 visits - 0 -
    - 9-14 visits - 0 -
    - 15-25 visits - 0 -
    - 26-50 visits - 0 -
    - 51-100 visits - 0 -
    - 101+ visits - 0 -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Visits to Conversion   + +  Conversions   +
    + 1 visit + 2 +
    + 2 visits + 2 +
    + 3 visits + 0 +
    + 4 visits + 0 +
    + 5 visits + 0 +
    + 6 visits + 0 +
    + 7 visits + 0 +
    + 8 visits + 0 +
    + 9-14 visits + 0 +
    + 15-25 visits + 0 +
    + 26-50 visits + 0 +
    + 51-100 visits + 0 +
    + 101+ visits + 0 +
    +
    + + Back to top +

    Ecommerce Orders - Days to Conversion

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Days to Conversion   - -  Conversions   -
    - 0 days - 4 -
    - 1 day - 0 -
    - 2 days - 0 -
    - 3 days - 0 -
    - 4 days - 0 -
    - 5 days - 0 -
    - 6 days - 0 -
    - 7 days - 0 -
    - 8-14 days - 0 -
    - 15-30 days - 0 -
    - 31-60 days - 0 -
    - 61-120 days - 0 -
    - 121-364 days - 0 -
    - 365+ days - 0 -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Days to Conversion   + +  Conversions   +
    + 0 days + 4 +
    + 1 day + 0 +
    + 2 days + 0 +
    + 3 days + 0 +
    + 4 days + 0 +
    + 5 days + 0 +
    + 6 days + 0 +
    + 7 days + 0 +
    + 8-14 days + 0 +
    + 15-30 days + 0 +
    + 31-60 days + 0 +
    + 61-120 days + 0 +
    + 121-364 days + 0 +
    + 365+ days + 0 +
    +
    + + Back to top +

    Abandoned Carts

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Name   - -  Value   -
    - Abandoned Carts - 3 -
    - Revenue left in cart - $ 7530.33 -
    - Products left in cart - 12 -
    - Average Order Value - $ 2510.11 -
    - Conversion Rate - 60% -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Name   + +  Value   +
    + Abandoned Carts + 3 +
    + Revenue left in cart + $ 7530.33 +
    + Products left in cart + 12 +
    + Average Order Value + $ 2510.11 +
    + Conversion Rate + 60% +
    +
    + + Back to top +

    Abandoned Carts - Visits to Conversion

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Visits to Conversion   - -  Conversions   -
    - 1 visit - 1 -
    - 2 visits - 2 -
    - 3 visits - 0 -
    - 4 visits - 0 -
    - 5 visits - 0 -
    - 6 visits - 0 -
    - 7 visits - 0 -
    - 8 visits - 0 -
    - 9-14 visits - 0 -
    - 15-25 visits - 0 -
    - 26-50 visits - 0 -
    - 51-100 visits - 0 -
    - 101+ visits - 0 -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Visits to Conversion   + +  Conversions   +
    + 1 visit + 1 +
    + 2 visits + 2 +
    + 3 visits + 0 +
    + 4 visits + 0 +
    + 5 visits + 0 +
    + 6 visits + 0 +
    + 7 visits + 0 +
    + 8 visits + 0 +
    + 9-14 visits + 0 +
    + 15-25 visits + 0 +
    + 26-50 visits + 0 +
    + 51-100 visits + 0 +
    + 101+ visits + 0 +
    +
    + + Back to top +

    Abandoned Carts - Days to Conversion

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Days to Conversion   - -  Conversions   -
    - 0 days - 3 -
    - 1 day - 0 -
    - 2 days - 0 -
    - 3 days - 0 -
    - 4 days - 0 -
    - 5 days - 0 -
    - 6 days - 0 -
    - 7 days - 0 -
    - 8-14 days - 0 -
    - 15-30 days - 0 -
    - 31-60 days - 0 -
    - 61-120 days - 0 -
    - 121-364 days - 0 -
    - 365+ days - 0 -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Days to Conversion   + +  Conversions   +
    + 0 days + 3 +
    + 1 day + 0 +
    + 2 days + 0 +
    + 3 days + 0 +
    + 4 days + 0 +
    + 5 days + 0 +
    + 6 days + 0 +
    + 7 days + 0 +
    + 8-14 days + 0 +
    + 15-30 days + 0 +
    + 31-60 days + 0 +
    + 61-120 days + 0 +
    + 121-364 days + 0 +
    + 365+ days + 0 +
    +
    + + Back to top +

    Product SKU

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Product SKU   - -  Product Revenue   - -  Quantity   - -  Unique Purchases   - -  Visits   - -  Average Price   - -  Average Quantity   - -  Product Conversion Rate   -
    - SKU2 - $ 1500 - - 1 - - 1 - - 1 - - $ 1500 - - 1 - - 100% -
    - SKU VERY nice indeed - $ 1011.22 - - 3 - - 2 - - 4 - - $ 255.61 - - 1.5 - - 50% -
    - ANOTHER SKU HERE - $ 600 - - 6 - - 1 - - 0 - - $ 100 - - 6 - - 0% -
    - TRIPOD SKU - $ 200 - - 2 - - 1 - - 0 - - $ 100 - - 2 - - 0% -
    - SKU IN ABANDONED CART TWO - $ 0 - - 0 - - 0 - - 3 - - $ 0 - - 0 - - 0% -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Product SKU   + +  Product Revenue   + +  Quantity   + +  Unique Purchases   + +  Visits   + +  Average Price   + +  Average Quantity   + +  Product Conversion Rate   +
    + SKU2 + $ 1500 + + 1 + + 1 + + 1 + + $ 1500 + + 1 + + 100% +
    + SKU VERY nice indeed + $ 1011.22 + + 3 + + 2 + + 4 + + $ 255.61 + + 1.5 + + 50% +
    + ANOTHER SKU HERE + $ 600 + + 6 + + 1 + + 0 + + $ 100 + + 6 + + 0% +
    + TRIPOD SKU + $ 200 + + 2 + + 1 + + 0 + + $ 100 + + 2 + + 0% +
    + SKU IN ABANDONED CART TWO + $ 0 + + 0 + + 0 + + 3 + + $ 0 + + 0 + + 0% +
    +
    + + Back to top +

    Product Name

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Product Name   - -  Product Revenue   - -  Quantity   - -  Unique Purchases   - -  Visits   - -  Average Price   - -  Average Quantity   - -  Product Conversion Rate   -
    - Canon SLR - $ 1500 - - 1 - - 1 - - 0 - - $ 1500 - - 1 - - 0% -
    - PRODUCT name - $ 1011.22 - - 3 - - 2 - - 2 - - $ 255.61 - - 1.5 - - 100% -
    - PRODUCT name BIS - $ 600 - - 6 - - 1 - - 0 - - $ 100 - - 6 - - 0% -
    - TRIPOD - bought day after - $ 200 - - 2 - - 1 - - 0 - - $ 100 - - 2 - - 0% -
    - PRODUCT THREE LEFT in cart - $ 0 - - 0 - - 0 - - 3 - - $ 1332 - - 0 - - 0% -
    - PRODUCT TWO LEFT in cart - $ 0 - - 0 - - 0 - - 3 - - $ 0 - - 0 - - 0% -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Product Name   + +  Product Revenue   + +  Quantity   + +  Unique Purchases   + +  Visits   + +  Average Price   + +  Average Quantity   + +  Product Conversion Rate   +
    + Canon SLR + $ 1500 + + 1 + + 1 + + 0 + + $ 1500 + + 1 + + 0% +
    + PRODUCT name + $ 1011.22 + + 3 + + 2 + + 2 + + $ 255.61 + + 1.5 + + 100% +
    + PRODUCT name BIS + $ 600 + + 6 + + 1 + + 0 + + $ 100 + + 6 + + 0% +
    + TRIPOD - bought day after + $ 200 + + 2 + + 1 + + 0 + + $ 100 + + 2 + + 0% +
    + PRODUCT THREE LEFT in cart + $ 0 + + 0 + + 0 + + 3 + + $ 1332 + + 0 + + 0% +
    + PRODUCT TWO LEFT in cart + $ 0 + + 0 + + 0 + + 3 + + $ 0 + + 0 + + 0% +
    +
    + + Back to top +

    Product Category

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Product Category   - -  Product Revenue   - -  Quantity   - -  Unique Purchases   - -  Visits   - -  Average Price   - -  Average Quantity   - -  Product Conversion Rate   -
    - Electronics & Cameras - $ 2500 - - 3 - - 2 - - 3 - - $ 1000 - - 1.5 - - 66.67% -
    - Multiple Category 1 - $ 1000 - - 2 - - 1 - - 1 - - $ 500 - - 2 - - 100% -
    - Multiple Category 2 - $ 1000 - - 2 - - 1 - - 1 - - $ 500 - - 2 - - 100% -
    - Multiple Category 4 - $ 1000 - - 2 - - 1 - - 1 - - $ 500 - - 2 - - 100% -
    - Multiple Category 5 - $ 1000 - - 2 - - 1 - - 1 - - $ 500 - - 2 - - 100% -
    - Product Category not defined - $ 611.22 - - 7 - - 2 - - 4 - - $ 55.61 - - 3.5 - - 50% -
    - Tools - $ 200 - - 2 - - 1 - - 0 - - $ 100 - - 2 - - 0% -
    - Category TWO LEFT in cart - $ 0 - - 0 - - 0 - - 3 - - $ 0 - - 0 - - 0% -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Product Category   + +  Product Revenue   + +  Quantity   + +  Unique Purchases   + +  Visits   + +  Average Price   + +  Average Quantity   + +  Product Conversion Rate   +
    + Electronics & Cameras + $ 2500 + + 3 + + 2 + + 3 + + $ 1000 + + 1.5 + + 66.67% +
    + Multiple Category 1 + $ 1000 + + 2 + + 1 + + 1 + + $ 500 + + 2 + + 100% +
    + Multiple Category 2 + $ 1000 + + 2 + + 1 + + 1 + + $ 500 + + 2 + + 100% +
    + Multiple Category 4 + $ 1000 + + 2 + + 1 + + 1 + + $ 500 + + 2 + + 100% +
    + Multiple Category 5 + $ 1000 + + 2 + + 1 + + 1 + + $ 500 + + 2 + + 100% +
    + Product Category not defined + $ 611.22 + + 7 + + 2 + + 4 + + $ 55.61 + + 3.5 + + 50% +
    + Tools + $ 200 + + 2 + + 1 + + 0 + + $ 100 + + 2 + + 0% +
    + Category TWO LEFT in cart + $ 0 + + 0 + + 0 + + 3 + + $ 0 + + 0 + + 0% +
    +
    + + Back to top +

    Actions - Main metrics

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Name   - -  Value   -
    - Pageviews - 16 -
    - Unique Pageviews - 4 -
    - Downloads - 0 -
    - Unique Downloads - 0 -
    - Outlinks - 0 -
    - Unique Outlinks - 0 -
    - Searches - 0 -
    - Unique Keywords - 0 -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Name   + +  Value   +
    + Pageviews + 16 +
    + Unique Pageviews + 4 +
    + Downloads + 0 +
    + Unique Downloads + 0 +
    + Outlinks + 0 +
    + Unique Outlinks + 0 +
    + Searches + 0 +
    + Unique Keywords + 0 +
    +
    + + Back to top +

    Page URLs

    - - - - - - - - - - - - - - - - - - - - - - -
    -  Page URL   - -  Pageviews   - -  Unique Pageviews   - -  Avg. time on page   - -  Bounce Rate   - -  Exit rate   -
    - - /index.htm - - 16 - - 4 - - 00:13:30 - - 0% - - 100% -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + +
    +  Page URL   + +  Pageviews   + +  Unique Pageviews   + +  Avg. time on page   + +  Bounce Rate   + +  Exit rate   +
    + + /index.htm + + 16 + + 4 + + 00:13:30 + + 0% + + 100% +
    +
    + + Back to top +

    Entry pages

    - - - - - - - - - - - - - - - - - - -
    -  Entry Page URL   - -  Entrances   - -  Bounces   - -  Bounce Rate   -
    - - /index.htm - - 3 - - 0 - - 0% -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + +
    +  Entry Page URL   + +  Entrances   + +  Bounces   + +  Bounce Rate   +
    + + /index.htm + + 3 + + 0 + + 0% +
    +
    + + Back to top +

    Exit pages

    - - - - - - - - - - - - - - - - - - -
    -  Exit Page URL   - -  Exits   - -  Unique Pageviews   - -  Exit rate   -
    - - /index.htm - - 4 - - 4 - - 100% -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + +
    +  Exit Page URL   + +  Exits   + +  Unique Pageviews   + +  Exit rate   +
    + + /index.htm + + 4 + + 4 + + 100% +
    +
    + + Back to top +

    Page titles

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Page Name   - -  Pageviews   - -  Unique Pageviews   - -  Avg. time on page   - -  Bounce Rate   - -  Exit rate   -
    - View product left in cart - 9 - - 3 - - 00:06:00 - - 0% - - 100% -
    - Another Product page - 1 - - 1 - - 00:06:00 - - 0% - - 0% -
    - Another Product page with multiple categories - 1 - - 1 - - 00:00:00 - - 0% - - 100% -
    - Another Product page with no category - 1 - - 1 - - 00:00:00 - - 0% - - 0% -
    - incredible title! - 1 - - 1 - - 00:06:00 - - 0% - - 0% -
    - Looking at Electronics & Cameras page again - 1 - - 1 - - 00:06:00 - - 0% - - 0% -
    - Looking at Electronics & Cameras page with a page level custom variable - 1 - - 1 - - 00:06:00 - - 0% - - 0% -
    - Looking at product page - 1 - - 1 - - 00:12:00 - - 0% - - 0% -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Page Name   + +  Pageviews   + +  Unique Pageviews   + +  Avg. time on page   + +  Bounce Rate   + +  Exit rate   +
    + View product left in cart + 9 + + 3 + + 00:06:00 + + 0% + + 100% +
    + Another Product page + 1 + + 1 + + 00:06:00 + + 0% + + 0% +
    + Another Product page with multiple categories + 1 + + 1 + + 00:00:00 + + 0% + + 100% +
    + Another Product page with no category + 1 + + 1 + + 00:00:00 + + 0% + + 0% +
    + incredible title! + 1 + + 1 + + 00:06:00 + + 0% + + 0% +
    + Looking at Electronics & Cameras page again + 1 + + 1 + + 00:06:00 + + 0% + + 0% +
    + Looking at Electronics & Cameras page with a page level custom variable + 1 + + 1 + + 00:06:00 + + 0% + + 0% +
    + Looking at product page + 1 + + 1 + + 00:12:00 + + 0% + + 0% +
    +
    + + Back to top +

    Entry page titles

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Entry Page title   - -  Entrances   - -  Bounces   - -  Bounce Rate   -
    - View product left in cart - 1 - - 0 - - 0% -
    - incredible title! - 1 - - 0 - - 0% -
    - Looking at Electronics & Cameras page with a page level custom variable - 1 - - 0 - - 0% -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Entry Page title   + +  Entrances   + +  Bounces   + +  Bounce Rate   +
    + View product left in cart + 1 + + 0 + + 0% +
    + incredible title! + 1 + + 0 + + 0% +
    + Looking at Electronics & Cameras page with a page level custom variable + 1 + + 0 + + 0% +
    +
    + + Back to top +

    Exit page titles

    - - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Exit Page Title   - -  Exits   - -  Unique Pageviews   - -  Exit rate   -
    - View product left in cart - 3 - - 3 - - 100% -
    - Another Product page with multiple categories - 1 - - 1 - - 100% -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Exit Page Title   + +  Exits   + +  Unique Pageviews   + +  Exit rate   +
    + View product left in cart + 3 + + 3 + + 100% +
    + Another Product page with multiple categories + 1 + + 1 + + 100% +
    +
    + + Back to top + - There is no data for this report. +There is no data for this report.

    Downloads

    - There is no data for this report. +There is no data for this report.

    Content Name

    - There is no data for this report. +There is no data for this report.

    Content Piece

    - There is no data for this report. +There is no data for this report.

    Event Categories

    - There is no data for this report. +There is no data for this report.

    Event Actions

    - There is no data for this report. +There is no data for this report.

    Event Names

    - There is no data for this report. +There is no data for this report.

    Site Search Keywords

    - There is no data for this report. +There is no data for this report.

    Search Keywords with No Results

    - There is no data for this report. +There is no data for this report.

    Search Categories

    - There is no data for this report. +There is no data for this report.

    Pages Following a Site Search

    - There is no data for this report. +There is no data for this report.

    Page Titles Following a Site Search

    - There is no data for this report. +There is no data for this report.

    Referrer Type

    - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Referrer Type   - -  Visits   - -  Actions   - -  Actions per Visit   - -  Avg. Time on Website   - -  Bounce Rate   - -  Revenue   -
    - Direct Entry - 5 - - 16 - - 3.2 - - 00:22:49 - - 20% - - $ 13361.11 -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Referrer Type   + +  Visits   + +  Actions   + +  Actions per Visit   + +  Avg. Time on Website   + +  Bounce Rate   + +  Revenue   +
    + Direct Entry + 5 + + 16 + + 3.2 + + 00:22:49 + + 20% + + $ 13361.11 +
    +
    + + Back to top +

    All Referrers

    - There is no data for this report. +There is no data for this report.

    Keywords

    - There is no data for this report. +There is no data for this report.

    Websites

    - There is no data for this report. +There is no data for this report.

    Search Engines

    - There is no data for this report. +There is no data for this report.

    Campaigns

    - There is no data for this report. +There is no data for this report.

    Social Networks

    - There is no data for this report. +There is no data for this report.

    Goals

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Name   - -  Value   -
    - Conversions - 5 -
    - Visits with Conversions - 4 -
    - Revenue - $ 13361.11 -
    - Conversion Rate - 80% -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Name   + +  Value   +
    + Conversions + 5 +
    + Visits with Conversions + 4 +
    + Revenue + $ 13361.11 +
    + Conversion Rate + 80% +
    +
    + + Back to top +

    Visits to Conversion

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Visits to Conversion   - -  Conversions   - -  Revenue   -
    - 1 visit - 1 - - $ 0 -
    - 2 visits - 0 - - $ 0 -
    - 3 visits - 0 - - $ 0 -
    - 4 visits - 0 - - $ 0 -
    - 5 visits - 0 - - $ 0 -
    - 6 visits - 0 - - $ 0 -
    - 7 visits - 0 - - $ 0 -
    - 8 visits - 0 - - $ 0 -
    - 9-14 visits - 0 - - $ 0 -
    - 15-25 visits - 0 - - $ 0 -
    - 26-50 visits - 0 - - $ 0 -
    - 51-100 visits - 0 - - $ 0 -
    - 101+ visits - 0 - - $ 0 -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Visits to Conversion   + +  Conversions   + +  Revenue   +
    + 1 visit + 1 + + $ 0 +
    + 2 visits + 0 + + $ 0 +
    + 3 visits + 0 + + $ 0 +
    + 4 visits + 0 + + $ 0 +
    + 5 visits + 0 + + $ 0 +
    + 6 visits + 0 + + $ 0 +
    + 7 visits + 0 + + $ 0 +
    + 8 visits + 0 + + $ 0 +
    + 9-14 visits + 0 + + $ 0 +
    + 15-25 visits + 0 + + $ 0 +
    + 26-50 visits + 0 + + $ 0 +
    + 51-100 visits + 0 + + $ 0 +
    + 101+ visits + 0 + + $ 0 +
    +
    + + Back to top +

    Days to Conversion

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Days to Conversion   - -  Conversions   - -  Revenue   -
    - 0 days - 1 - - $ 0 -
    - 1 day - 0 - - $ 0 -
    - 2 days - 0 - - $ 0 -
    - 3 days - 0 - - $ 0 -
    - 4 days - 0 - - $ 0 -
    - 5 days - 0 - - $ 0 -
    - 6 days - 0 - - $ 0 -
    - 7 days - 0 - - $ 0 -
    - 8-14 days - 0 - - $ 0 -
    - 15-30 days - 0 - - $ 0 -
    - 31-60 days - 0 - - $ 0 -
    - 61-120 days - 0 - - $ 0 -
    - 121-364 days - 0 - - $ 0 -
    - 365+ days - 0 - - $ 0 -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Days to Conversion   + +  Conversions   + +  Revenue   +
    + 0 days + 1 + + $ 0 +
    + 1 day + 0 + + $ 0 +
    + 2 days + 0 + + $ 0 +
    + 3 days + 0 + + $ 0 +
    + 4 days + 0 + + $ 0 +
    + 5 days + 0 + + $ 0 +
    + 6 days + 0 + + $ 0 +
    + 7 days + 0 + + $ 0 +
    + 8-14 days + 0 + + $ 0 +
    + 15-30 days + 0 + + $ 0 +
    + 31-60 days + 0 + + $ 0 +
    + 61-120 days + 0 + + $ 0 +
    + 121-364 days + 0 + + $ 0 +
    + 365+ days + 0 + + $ 0 +
    +
    + + Back to top +

    Goal title match, triggered ONCE

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Name   - -  Value   -
    - Conversions - 1 -
    - Visits with Conversions - 1 -
    - Revenue - $ 10 -
    - Conversion Rate - 20% -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Name   + +  Value   +
    + Conversions + 1 +
    + Visits with Conversions + 1 +
    + Revenue + $ 10 +
    + Conversion Rate + 20% +
    +
    + + Back to top +

    title match, triggered ONCE - Visits to Conversion

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Visits to Conversion   - -  Conversions   -
    - 1 visit - 1 -
    - 2 visits - 0 -
    - 3 visits - 0 -
    - 4 visits - 0 -
    - 5 visits - 0 -
    - 6 visits - 0 -
    - 7 visits - 0 -
    - 8 visits - 0 -
    - 9-14 visits - 0 -
    - 15-25 visits - 0 -
    - 26-50 visits - 0 -
    - 51-100 visits - 0 -
    - 101+ visits - 0 -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Visits to Conversion   + +  Conversions   +
    + 1 visit + 1 +
    + 2 visits + 0 +
    + 3 visits + 0 +
    + 4 visits + 0 +
    + 5 visits + 0 +
    + 6 visits + 0 +
    + 7 visits + 0 +
    + 8 visits + 0 +
    + 9-14 visits + 0 +
    + 15-25 visits + 0 +
    + 26-50 visits + 0 +
    + 51-100 visits + 0 +
    + 101+ visits + 0 +
    +
    + + Back to top +

    title match, triggered ONCE - Days to Conversion

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Days to Conversion   - -  Conversions   -
    - 0 days - 1 -
    - 1 day - 0 -
    - 2 days - 0 -
    - 3 days - 0 -
    - 4 days - 0 -
    - 5 days - 0 -
    - 6 days - 0 -
    - 7 days - 0 -
    - 8-14 days - 0 -
    - 15-30 days - 0 -
    - 31-60 days - 0 -
    - 61-120 days - 0 -
    - 121-364 days - 0 -
    - 365+ days - 0 -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Days to Conversion   + +  Conversions   +
    + 0 days + 1 +
    + 1 day + 0 +
    + 2 days + 0 +
    + 3 days + 0 +
    + 4 days + 0 +
    + 5 days + 0 +
    + 6 days + 0 +
    + 7 days + 0 +
    + 8-14 days + 0 +
    + 15-30 days + 0 +
    + 31-60 days + 0 +
    + 61-120 days + 0 +
    + 121-364 days + 0 +
    + 365+ days + 0 +
    +
    + + Back to top +

    Country

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Country   - -  Visits   - -  Actions   - -  Actions per Visit   - -  Avg. Time on Website   - -  Bounce Rate   - -  Revenue   -
    - -   - Poland - 4 - - 12 - - 3 - - 00:25:32 - - 25% - - $ 13351.11 -
    - -   - France - 1 - - 4 - - 4 - - 00:12:01 - - 0% - - $ 10 -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Country   + +  Visits   + +  Actions   + +  Actions per Visit   + +  Avg. Time on Website   + +  Bounce Rate   + +  Revenue   +
    + +   + Poland + 4 + + 12 + + 3 + + 00:25:32 + + 25% + + $ 13351.11 +
    + +   + France + 1 + + 4 + + 4 + + 00:12:01 + + 0% + + $ 10 +
    +
    + + Back to top +

    Continent

    - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Continent   - -  Visits   - -  Actions   - -  Actions per Visit   - -  Avg. Time on Website   - -  Bounce Rate   - -  Revenue   -
    - Europe - 5 - - 16 - - 3.2 - - 00:22:49 - - 20% - - $ 13361.11 -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Continent   + +  Visits   + +  Actions   + +  Actions per Visit   + +  Avg. Time on Website   + +  Bounce Rate   + +  Revenue   +
    + Europe + 5 + + 16 + + 3.2 + + 00:22:49 + + 20% + + $ 13361.11 +
    +
    + + Back to top +

    Region

    - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Region   - -  Visits   - -  Actions   - -  Actions per Visit   - -  Avg. Time on Website   - -  Bounce Rate   - -  Revenue   -
    - -   - Unknown - 5 - - 16 - - 3.2 - - 00:22:49 - - 20% - - $ 13361.11 -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Region   + +  Visits   + +  Actions   + +  Actions per Visit   + +  Avg. Time on Website   + +  Bounce Rate   + +  Revenue   +
    + +   + Unknown + 5 + + 16 + + 3.2 + + 00:22:49 + + 20% + + $ 13361.11 +
    +
    + + Back to top +

    City

    - - - - - - - - - - - - - - - - - - - - - - - - -
    -  City   - -  Visits   - -  Actions   - -  Actions per Visit   - -  Avg. Time on Website   - -  Bounce Rate   - -  Revenue   -
    - -   - Unknown - 5 - - 16 - - 3.2 - - 00:22:49 - - 20% - - $ 13361.11 -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + +
    +  City   + +  Visits   + +  Actions   + +  Actions per Visit   + +  Avg. Time on Website   + +  Bounce Rate   + +  Revenue   +
    + +   + Unknown + 5 + + 16 + + 3.2 + + 00:22:49 + + 20% + + $ 13361.11 +
    +
    + + Back to top +

    Custom Variables

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Custom Variable name   - -  Visits   - -  Actions   - -  Actions per Visit   - -  Avg. Time on Website   - -  Bounce Rate   - -  Revenue   -
    - ValueIsZero - 5 - - 16 - - 3.2 - - 00:22:49 - - 20% - - $ 13361.11 -
    - VisitorType - 5 - - 16 - - 3.2 - - 00:22:49 - - 20% - - $ 13361.11 -
    - VisitorName - 4 - - 12 - - 3 - - 00:25:32 - - 25% - - $ 13351.11 -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Custom Variable name   + +  Visits   + +  Actions   + +  Actions per Visit   + +  Avg. Time on Website   + +  Bounce Rate   + +  Revenue   +
    + ValueIsZero + 5 + + 16 + + 3.2 + + 00:22:49 + + 20% + + $ 13361.11 +
    + VisitorType + 5 + + 16 + + 3.2 + + 00:22:49 + + 20% + + $ 13361.11 +
    + VisitorName + 4 + + 12 + + 3 + + 00:25:32 + + 25% + + $ 13351.11 +
    +
    + + Back to top +

    Length of Visits

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Visit duration   - -  Visits   -
    - 0-10s - 0 -
    - 11-30s - 0 -
    - 31-60s - 0 -
    - 1-2 min - 0 -
    - 2-4 min - 0 -
    - 4-7 min - 1 -
    - 7-10 min - 0 -
    - 10-15 min - 2 -
    - 15-30 min - 1 -
    - 30+ min - 1 -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Visit duration   + +  Visits   +
    + 0-10s + 0 +
    + 11-30s + 0 +
    + 31-60s + 0 +
    + 1-2 min + 0 +
    + 2-4 min + 0 +
    + 4-7 min + 1 +
    + 7-10 min + 0 +
    + 10-15 min + 2 +
    + 15-30 min + 1 +
    + 30+ min + 1 +
    +
    + + Back to top +

    Pages per Visit

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Pages per visit   - -  Visits   -
    - 1 page - 0 -
    - 2 pages - 0 -
    - 3 pages - 2 -
    - 4 pages - 1 -
    - 5 pages - 0 -
    - 6-7 pages - 1 -
    - 8-10 pages - 0 -
    - 11-14 pages - 0 -
    - 15-20 pages - 0 -
    - 21+ pages - 0 -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Pages per visit   + +  Visits   +
    + 1 page + 0 +
    + 2 pages + 0 +
    + 3 pages + 2 +
    + 4 pages + 1 +
    + 5 pages + 0 +
    + 6-7 pages + 1 +
    + 8-10 pages + 0 +
    + 11-14 pages + 0 +
    + 15-20 pages + 0 +
    + 21+ pages + 0 +
    +
    + + Back to top +

    Visits by Visit Number

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Visits by Visit Number   - -  Visits   - -  % Visits   -
    - 1 visit - 3 - - 60% -
    - 2 visits - 2 - - 40% -
    - 3 visits - 0 - - 0% -
    - 4 visits - 0 - - 0% -
    - 5 visits - 0 - - 0% -
    - 6 visits - 0 - - 0% -
    - 7 visits - 0 - - 0% -
    - 8 visits - 0 - - 0% -
    - 9-14 visits - 0 - - 0% -
    - 15-25 visits - 0 - - 0% -
    - 26-50 visits - 0 - - 0% -
    - 51-100 visits - 0 - - 0% -
    - 101-200 visits - 0 - - 0% -
    - 201+ visits - 0 - - 0% -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Visits by Visit Number   + +  Visits   + +  % Visits   +
    + 1 visit + 3 + + 60% +
    + 2 visits + 2 + + 40% +
    + 3 visits + 0 + + 0% +
    + 4 visits + 0 + + 0% +
    + 5 visits + 0 + + 0% +
    + 6 visits + 0 + + 0% +
    + 7 visits + 0 + + 0% +
    + 8 visits + 0 + + 0% +
    + 9-14 visits + 0 + + 0% +
    + 15-25 visits + 0 + + 0% +
    + 26-50 visits + 0 + + 0% +
    + 51-100 visits + 0 + + 0% +
    + 101-200 visits + 0 + + 0% +
    + 201+ visits + 0 + + 0% +
    +
    + + Back to top +

    Visits by days since last visit

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Visits by days since last visit   - -  Visits   -
    - New visits - 1 -
    - 0 days - 1 -
    - 1 day - 0 -
    - 2 days - 0 -
    - 3 days - 0 -
    - 4 days - 0 -
    - 5 days - 0 -
    - 6 days - 0 -
    - 7 days - 0 -
    - 8-14 days - 0 -
    - 15-30 days - 0 -
    - 31-60 days - 0 -
    - 61-120 days - 0 -
    - 121-364 days - 0 -
    - 365+ days - 0 -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Visits by days since last visit   + +  Visits   +
    + New visits + 1 +
    + 0 days + 1 +
    + 1 day + 0 +
    + 2 days + 0 +
    + 3 days + 0 +
    + 4 days + 0 +
    + 5 days + 0 +
    + 6 days + 0 +
    + 7 days + 0 +
    + 8-14 days + 0 +
    + 15-30 days + 0 +
    + 31-60 days + 0 +
    + 61-120 days + 0 +
    + 121-364 days + 0 +
    + 365+ days + 0 +
    +
    + + Back to top +

    Returning Visits

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Name   - -  Value   -
    - Unique returning visitors - 1 -
    - Returning Users - 0 -
    - Returning Visits - 4 -
    - Actions by Returning Visits - 12 -
    - Maximum actions in one returning visit - 6 -
    - Bounce Rate for Returning Visits - 25% -
    - Avg. Actions per Returning Visit - 3 -
    - Avg. Duration of a Returning Visit (in sec) - 00:25:32 -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Name   + +  Value   +
    + Unique returning visitors + 1 +
    + Returning Users + 0 +
    + Returning Visits + 4 +
    + Actions by Returning Visits + 12 +
    + Maximum actions in one returning visit + 6 +
    + Bounce Rate for Returning Visits + 25% +
    + Avg. Actions per Returning Visit + 3 +
    + Avg. Duration of a Returning Visit (in sec) + 00:25:32 +
    +
    + + Back to top + +

    + Provider +

    + + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Provider   + +  Visits   + +  Actions   + +  Actions per Visit   + +  Avg. Time on Website   + +  Bounce Rate   + +  Conversion Rate   +
    + + Unknown + + 5 + + 16 + + 3.2 + + 00:22:49 + + 20% + + 80% +
    +
    + + Back to top +

    Device type

    - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Device type   - -  Visits   - -  Actions   - -  Actions per Visit   - -  Avg. Time on Website   - -  Bounce Rate   - -  Conversion Rate   -
    - -   - Desktop - 5 - - 16 - - 3.2 - - 00:22:49 - - 20% - - 80% -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Device type   + +  Visits   + +  Actions   + +  Actions per Visit   + +  Avg. Time on Website   + +  Bounce Rate   + +  Conversion Rate   +
    + +   + Desktop + 5 + + 16 + + 3.2 + + 00:22:49 + + 20% + + 80% +
    +
    + + Back to top +

    Visitor Browser

    - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Browser   - -  Visits   - -  Actions   - -  Actions per Visit   - -  Avg. Time on Website   - -  Bounce Rate   - -  Conversion Rate   -
    - -   - Firefox - 5 - - 16 - - 3.2 - - 00:22:49 - - 20% - - 80% -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Browser   + +  Visits   + +  Actions   + +  Actions per Visit   + +  Avg. Time on Website   + +  Bounce Rate   + +  Conversion Rate   +
    + +   + Firefox + 5 + + 16 + + 3.2 + + 00:22:49 + + 20% + + 80% +
    +
    + + Back to top +

    Device brand

    - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Device brand   - -  Visits   - -  Actions   - -  Actions per Visit   - -  Avg. Time on Website   - -  Bounce Rate   - -  Conversion Rate   -
    - -   - Unknown - 5 - - 16 - - 3.2 - - 00:22:49 - - 20% - - 80% -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Device brand   + +  Visits   + +  Actions   + +  Actions per Visit   + +  Avg. Time on Website   + +  Bounce Rate   + +  Conversion Rate   +
    + +   + Unknown + 5 + + 16 + + 3.2 + + 00:22:49 + + 20% + + 80% +
    +
    + + Back to top +

    Browser version

    - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Browser version   - -  Visits   - -  Actions   - -  Actions per Visit   - -  Avg. Time on Website   - -  Bounce Rate   - -  Conversion Rate   -
    - -   - Firefox 3.6 - 5 - - 16 - - 3.2 - - 00:22:49 - - 20% - - 80% -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Browser version   + +  Visits   + +  Actions   + +  Actions per Visit   + +  Avg. Time on Website   + +  Bounce Rate   + +  Conversion Rate   +
    + +   + Firefox 3.6 + 5 + + 16 + + 3.2 + + 00:22:49 + + 20% + + 80% +
    +
    + + Back to top +

    Device model

    - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Device model   - -  Visits   - -  Actions   - -  Actions per Visit   - -  Avg. Time on Website   - -  Bounce Rate   - -  Conversion Rate   -
    - Unknown - 5 - - 16 - - 3.2 - - 00:22:49 - - 20% - - 80% -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Device model   + +  Visits   + +  Actions   + +  Actions per Visit   + +  Avg. Time on Website   + +  Bounce Rate   + +  Conversion Rate   +
    + Unknown + 5 + + 16 + + 3.2 + + 00:22:49 + + 20% + + 80% +
    +
    + + Back to top +

    Operating System families

    - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Operating system family   - -  Visits   - -  Actions   - -  Actions per Visit   - -  Avg. Time on Website   - -  Bounce Rate   - -  Conversion Rate   -
    - -   - Windows - 5 - - 16 - - 3.2 - - 00:22:49 - - 20% - - 80% -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Operating system family   + +  Visits   + +  Actions   + +  Actions per Visit   + +  Avg. Time on Website   + +  Bounce Rate   + +  Conversion Rate   +
    + +   + Windows + 5 + + 16 + + 3.2 + + 00:22:49 + + 20% + + 80% +
    +
    + + Back to top +

    Operating System versions

    - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Operating System versions   - -  Visits   - -  Actions   - -  Actions per Visit   - -  Avg. Time on Website   - -  Bounce Rate   - -  Conversion Rate   -
    - -   - Windows XP - 5 - - 16 - - 3.2 - - 00:22:49 - - 20% - - 80% -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Operating System versions   + +  Visits   + +  Actions   + +  Actions per Visit   + +  Avg. Time on Website   + +  Bounce Rate   + +  Conversion Rate   +
    + +   + Windows XP + 5 + + 16 + + 3.2 + + 00:22:49 + + 20% + + 80% +
    +
    + + Back to top +

    Browser engines

    - - - - - - - - - - - - - - - - - - - - - - - - -
    -  Browser engine   - -  Visits   - -  Actions   - -  Actions per Visit   - -  Avg. Time on Website   - -  Bounce Rate   - -  Conversion Rate   -
    - Gecko (Firefox) - 5 - - 16 - - 3.2 - - 00:22:49 - - 20% - - 80% -
    -
    - - Back to top - + + + + + + + + + + + + + + + + + + + + + + + + +
    +  Browser engine   + +  Visits   + +  Actions   + +  Actions per Visit   + +  Avg. Time on Website   + +  Bounce Rate   + +  Conversion Rate   +
    + Gecko (Firefox) + 5 + + 16 + + 3.2 + + 00:22:49 + + 20% + + 80% +
    +
    + + Back to top + \ No newline at end of file diff --git a/tests/PHPUnit/System/expected/test_periodIsRange_dateIsLastN_MetadataAndNormalAPI__API.getProcessedReport_range.xml b/tests/PHPUnit/System/expected/test_periodIsRange_dateIsLastN_MetadataAndNormalAPI__API.getProcessedReport_range.xml index 61d15c6685..c866fba5b5 100644 --- a/tests/PHPUnit/System/expected/test_periodIsRange_dateIsLastN_MetadataAndNormalAPI__API.getProcessedReport_range.xml +++ b/tests/PHPUnit/System/expected/test_periodIsRange_dateIsLastN_MetadataAndNormalAPI__API.getProcessedReport_range.xml @@ -4,6 +4,7 @@ Visitors + Locations Country UserCountry getCountry diff --git a/tests/PHPUnit/System/expected/test_periodIsRange_dateIsLastN_MetadataAndNormalAPI_pagesegment__API.getProcessedReport_range.xml b/tests/PHPUnit/System/expected/test_periodIsRange_dateIsLastN_MetadataAndNormalAPI_pagesegment__API.getProcessedReport_range.xml index 61d15c6685..c866fba5b5 100644 --- a/tests/PHPUnit/System/expected/test_periodIsRange_dateIsLastN_MetadataAndNormalAPI_pagesegment__API.getProcessedReport_range.xml +++ b/tests/PHPUnit/System/expected/test_periodIsRange_dateIsLastN_MetadataAndNormalAPI_pagesegment__API.getProcessedReport_range.xml @@ -4,6 +4,7 @@ Visitors + Locations Country UserCountry getCountry diff --git a/tests/PHPUnit/Unit/Category/CategoryListTest.php b/tests/PHPUnit/Unit/Category/CategoryListTest.php new file mode 100644 index 0000000000..53f5d9c42c --- /dev/null +++ b/tests/PHPUnit/Unit/Category/CategoryListTest.php @@ -0,0 +1,92 @@ +categoryList = new CategoryList(); + } + + public function test_getCategories_IsEmptyByDefault() + { + $this->assertSame(array(), $this->categoryList->getCategories()); + } + + public function test_addCategory_ShouldAddCategory_and_getCategories_shouldBeIndexedById() + { + $category = $this->addCategory('myTest'); + + $this->assertSame(array('myTest' => $category), $this->categoryList->getCategories()); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Category myTest already exists + */ + public function test_addCategory_shouldThrowException_IfAddingSameCategoryIdTwice() + { + $this->addCategory('myTest'); + $this->addCategory('myTest'); + } + + public function test_hasCategory_ShouldDetectIfCategoryExists() + { + $this->assertFalse($this->categoryList->hasCategory('myTest')); + + $this->addCategory('myTest'); + + $this->assertTrue($this->categoryList->hasCategory('myTest')); + + $this->assertFalse($this->categoryList->hasCategory('myTest2')); + $this->assertFalse($this->categoryList->hasCategory('General_Visits')); + } + + public function test_getCategory_ShouldReturnExistingCategoryIfPossible() + { + $this->assertNull($this->categoryList->getCategory('myTest')); + + $category = $this->addCategory('myTest'); + + $this->assertSame($category, $this->categoryList->getCategory('myTest')); + + $this->assertNull($this->categoryList->getCategory('myTest2')); + $this->assertNull($this->categoryList->getCategory('General_Visits')); + } + + private function addCategory($id) + { + $category = $this->createCategory($id); + $this->categoryList->addCategory($category); + + return $category; + } + + private function createCategory($categoryId) + { + $config = new Category(); + $config->setId($categoryId); + + return $config; + } +} diff --git a/tests/PHPUnit/Unit/Category/CategoryTest.php b/tests/PHPUnit/Unit/Category/CategoryTest.php new file mode 100644 index 0000000000..de4b931657 --- /dev/null +++ b/tests/PHPUnit/Unit/Category/CategoryTest.php @@ -0,0 +1,141 @@ +category = new Category(); + } + + public function test_order_set_get() + { + $this->category->setOrder(99); + $this->assertSame(99, $this->category->getOrder()); + + $this->category->setOrder('98'); + $this->assertSame(98, $this->category->getOrder()); + } + + public function test_getOrder_shouldReturnADefaultValue() + { + $this->assertSame(99, $this->category->getOrder()); + } + + public function test_id_set_get() + { + $this->category->setId('myCustomId'); + $this->assertSame('myCustomId', $this->category->getId()); + } + + public function test_getId_shouldBeEmptyStringByDefault() + { + $this->assertSame('', $this->category->getId()); + } + + public function test_getSubcategories_ShouldReturnAnEmptyArray_ByDefault() + { + $this->assertSame(array(), $this->category->getSubcategories()); + } + + public function test_addSubcategory_ShouldActuallyAddAndReturnSubcategories() + { + $subcategory1 = $this->createSubcategory('id1', 'name1'); + $subcategory2 = $this->createSubcategory('id2', 'name2'); + + $this->category->addSubcategory($subcategory1); + $this->category->addSubcategory($subcategory2); + + $this->assertSame(array($subcategory1, $subcategory2), $this->category->getSubcategories()); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Subcategory id1 already exists + */ + public function test_addSubcategory_ShouldThrowException_WhenAddingSubcategoryWithSameIdTwice() + { + $subcategory1 = $this->createSubcategory('id1', 'name1'); + $subcategory2 = $this->createSubcategory('id1', 'name2'); + + $this->category->addSubcategory($subcategory1); + $this->category->addSubcategory($subcategory2); + } + + public function test_hasSubcategories_ShouldDetectIfSubcategoriesArePresent() + { + $this->assertFalse($this->category->hasSubCategories()); + $this->addSubcategories(array('myid' => 'myname')); + $this->assertTrue($this->category->hasSubCategories()); + } + + public function test_getSubcategory_ShouldNotFindASubCategoryById_IfSuchCategoryDoesNotExist() + { + $this->assertNull($this->category->getSubcategory('myid')); + } + + public function test_getSubcategory_ShouldFindAnExistingSubCategoryById() + { + $this->addSubcategories(array('myid' => 'myname', 'myid2' => 'myname2')); + + $subcategory = $this->category->getSubcategory('myid2'); + $this->assertTrue($subcategory instanceof Subcategory); + $this->assertSame('myname2', $subcategory->getName()); + } + + public function test_getSubcategory_ShouldNotFindASubcategoryByName() + { + $this->addSubcategories(array('myid' => 'myname')); + + $this->assertNull($this->category->getSubcategory('myname')); + } + + public function test_hasSubcategory_ShouldActuallyAddTheConfig() + { + $this->assertFalse($this->category->hasSubcategory('myid2')); + + $this->addSubcategories(array('myid' => 'myname', 'myid2' => 'myname2')); + + $this->assertTrue($this->category->hasSubcategory('myid2')); + $this->assertFalse($this->category->hasSubcategory('myname')); + $this->assertFalse($this->category->hasSubcategory('myname2')); + $this->assertFalse($this->category->hasSubcategory('mySomething')); + } + + private function addSubcategories($subcategories) + { + foreach ($subcategories as $id => $name) { + $this->category->addSubcategory($this->createSubcategory($id, $name)); + } + } + + private function createSubcategory($subcategoryId, $subcategoryName) + { + $config = new Subcategory(); + $config->setId($subcategoryId); + $config->setName($subcategoryName); + + return $config; + } +} diff --git a/tests/PHPUnit/Unit/Category/SubcategoryTest.php b/tests/PHPUnit/Unit/Category/SubcategoryTest.php new file mode 100644 index 0000000000..463ea22b6d --- /dev/null +++ b/tests/PHPUnit/Unit/Category/SubcategoryTest.php @@ -0,0 +1,89 @@ +subcategory = new Subcategory(); + } + + public function test_categoryId_set_get() + { + $this->subcategory->setCategoryId('testCategory'); + + $this->assertSame('testCategory', $this->subcategory->getCategoryId()); + } + + public function test_getCategoryId_shouldBeEmptyStringByDefault() + { + $this->assertSame('', $this->subcategory->getCategoryId()); + } + + public function test_name_set_get() + { + $this->subcategory->setName('testName'); + + $this->assertSame('testName', $this->subcategory->getName()); + } + + public function test_getName_shouldBeEmptyStringByDefault() + { + $this->assertSame('', $this->subcategory->getName()); + } + + public function test_getName_ShouldDefaultToId_IfNoNameIsSet() + { + $this->subcategory->setId('myTestId'); + + $this->assertSame('myTestId', $this->subcategory->getName()); + $this->assertSame('myTestId', $this->subcategory->getId()); + } + + public function test_order_set_get() + { + $this->subcategory->setOrder(99); + $this->assertSame(99, $this->subcategory->getOrder()); + + $this->subcategory->setOrder('98'); + $this->assertSame(98, $this->subcategory->getOrder()); + } + + public function test_getOrder_shouldReturnADefaultValue() + { + $this->assertSame(99, $this->subcategory->getOrder()); + } + + public function test_id_set_get() + { + $this->subcategory->setId('myCustomId'); + $this->assertSame('myCustomId', $this->subcategory->getId()); + } + + public function test_getId_shouldBeEmptyStringByDefault() + { + $this->assertSame('', $this->subcategory->getId()); + } + +} diff --git a/tests/PHPUnit/Unit/Report/ReportWidgetConfigTest.php b/tests/PHPUnit/Unit/Report/ReportWidgetConfigTest.php new file mode 100644 index 0000000000..d1ac8d4021 --- /dev/null +++ b/tests/PHPUnit/Unit/Report/ReportWidgetConfigTest.php @@ -0,0 +1,262 @@ +config = new ReportWidgetConfig(); + } + + public function test_getViewDataTable_ByDefaultThereShouldBeNoDefaultView() + { + $this->assertNull($this->config->getViewDataTable()); + } + + public function test_setDefaultViewDataTable() + { + $this->config->setDefaultViewDataTable('table'); + + $this->assertSame('table', $this->config->getViewDataTable()); + $this->assertFalse($this->config->isViewDataTableForced()); + } + + public function test_forceViewDataTable() + { + $this->config->forceViewDataTable('table'); + + $this->assertSame('table', $this->config->getViewDataTable()); + $this->assertTrue($this->config->isViewDataTableForced()); + } + + public function test_name_set_get() + { + $this->config->setName('testName'); + + $this->assertSame('testName', $this->config->getName()); + } + + public function test_getName_shouldBeEmptyStringByDefault() + { + $this->assertSame('', $this->config->getName()); + } + + public function test_categoryId_set_get() + { + $this->config->setCategoryId('testCat'); + + $this->assertSame('testCat', $this->config->getCategoryId()); + } + + public function test_getCategoryId_shouldBeEmptyStringByDefault() + { + $this->assertSame('', $this->config->getCategoryId()); + } + + public function test_subcategoryId_set_get() + { + $this->config->setSubcategoryId('testsubcat'); + + $this->assertSame('testsubcat', $this->config->getSubcategoryId()); + } + + public function test_getSubcategoryId_shouldBeEmptyStringByDefault() + { + $this->assertSame('', $this->config->getSubcategoryId()); + } + + public function test_module_set_get() + { + $this->config->setModule('CoreHome'); + + $this->assertSame('CoreHome', $this->config->getModule()); + } + + public function test_getModule_shouldBeEmptyStringByDefault() + { + $this->assertSame('', $this->config->getModule()); + } + + public function test_action_set_get() + { + $this->config->setAction('get'); + + $this->assertSame('get', $this->config->getAction()); + } + + public function test_getAction_shouldBeEmptyStringByDefault() + { + $this->assertSame('', $this->config->getAction()); + } + + public function test_order_set_get() + { + $this->config->setOrder(99); + $this->assertSame(99, $this->config->getOrder()); + + $this->config->setOrder('98'); + $this->assertSame(98, $this->config->getOrder()); + } + + public function test_getOrder_shouldReturnADefaultValue() + { + $this->assertSame(99, $this->config->getOrder()); + } + + public function test_setMiddlewareParameters_set_get() + { + $this->config->setMiddlewareParameters(array( + 'module' => 'Goals', + 'action' => 'hasConversions' + )); + + $this->assertSame(array( + 'module' => 'Goals', + 'action' => 'hasConversions' + ), $this->config->getMiddlewareParameters()); + } + + public function test_getMiddlewareParameters_shouldReturnADefaultValue() + { + $this->assertSame(array(), $this->config->getMiddlewareParameters()); + } + + public function test_getParameters_ShouldAddModuleAndAction() + { + $this->setModuleAndAction(); + $this->assertSame(array('module' => 'CoreHome', 'action' => 'renderMe'), $this->config->getParameters()); + } + + public function test_getParameters_ShouldNotBePossibleToOverwriteModuleAndAction() + { + $this->setModuleAndAction(); + $this->config->setParameters(array('module' => 'Actions', 'action' => 'index')); + + $this->assertSame(array('module' => 'CoreHome', 'action' => 'renderMe'), $this->config->getParameters()); + } + + public function test_getParameters_ShouldReturnViewDataTableIfSet() + { + $this->setModuleAndAction(); + $this->config->setDefaultViewDataTable('graph'); + + $this->assertSame(array('viewDataTable' => 'graph', 'module' => 'CoreHome', 'action' => 'renderMe'), $this->config->getParameters()); + } + + public function test_getParameters_ShouldForceViewDataTableIfSet() + { + $this->setModuleAndAction(); + $this->config->forceViewDataTable('graph'); + + $this->assertSame(array('forceView' => '1', 'viewDataTable' => 'graph', 'module' => 'CoreHome', 'action' => 'renderMe'), $this->config->getParameters()); + } + + public function test_addParameters_ShouldAddMoreParams() + { + $this->setModuleAndAction(); + $this->config->addParameters(array('test' => '1')); // should be removed by setParameters + $this->config->addParameters(array('forceView' => '1')); + $this->config->addParameters(array('test' => '3')); + + $this->assertSame(array('module' => 'CoreHome', 'action' => 'renderMe', 'test' => '3', 'forceView' => '1'), $this->config->getParameters()); + } + + public function test_setParameters_ShouldOverwriteAnyExistingParameters() + { + $this->setModuleAndAction(); + $this->config->addParameters(array('test' => '1')); // should be removed by setParameters + $this->config->setParameters(array('forceView' => '1')); + + $this->assertSame(array('module' => 'CoreHome', 'action' => 'renderMe', 'forceView' => '1'), $this->config->getParameters()); + } + + public function test_shouldBeEnabledByDefault() + { + $this->assertTrue($this->config->isEnabled()); + } + + public function test_enable_disable() + { + $this->config->disable(); + $this->assertFalse($this->config->isEnabled()); + $this->config->enable(); + $this->assertTrue($this->config->isEnabled()); + } + + public function test_setIsEnabled() + { + $this->config->setIsEnabled(false); + $this->assertFalse($this->config->isEnabled()); + $this->config->setIsEnabled(true); + $this->assertTrue($this->config->isEnabled()); + } + + public function test_checkIsEnabled_shouldNotThrowException_IfEnabled() + { + $this->config->enable(); + $this->config->checkIsEnabled(); + } + + /** + * @expectedException \Exception + */ + public function test_checkIsEnabled_shouldThrowException_IfDisabled() + { + $this->config->disable(); + $this->config->checkIsEnabled(); + } + + public function test_shouldBeWidgetizable_ByDefault() + { + $this->assertTrue($this->config->isWidgetizeable()); + } + + public function test_widgetizeable() + { + $this->config->setIsNotWidgetizable(); + $this->assertFalse($this->config->isWidgetizeable()); + $this->config->setIsWidgetizable(); + $this->assertTrue($this->config->isWidgetizeable()); + } + + public function test_getUniqueId_withNoParameters() + { + $this->setModuleAndAction(); + $this->assertSame('widgetCoreHomerenderMe', $this->config->getUniqueId()); + } + + public function test_getUniqueId_withParameters() + { + $this->setModuleAndAction(); + $this->config->addParameters(array('viewDataTable' => 'table', 'forceView' => '1', 'mtest' => array('test'))); + $this->assertSame('widgetCoreHomerenderMeviewDataTabletableforceView1mtestArray', $this->config->getUniqueId()); + } + + private function setModuleAndAction() + { + $this->config->setModule('CoreHome'); + $this->config->setAction('renderMe'); + } + +} diff --git a/tests/PHPUnit/Unit/Report/ReportWidgetFactoryTest.php b/tests/PHPUnit/Unit/Report/ReportWidgetFactoryTest.php new file mode 100644 index 0000000000..2f49fee3cb --- /dev/null +++ b/tests/PHPUnit/Unit/Report/ReportWidgetFactoryTest.php @@ -0,0 +1,112 @@ +name = 'Report_MyCustomReportName'; + $this->order = 20; + $this->module = 'TestPlugin'; + $this->action = 'getBasicReport'; + $this->categoryId = 'Goals_Goals'; + $this->subcategoryId = 'General_Overview'; + $this->actionToLoadSubTables = 'invalidReport'; + $this->parameters = array('idGoal' => '1'); + } + + public function getDefaultTypeViewDataTable() + { + return 'graph'; + } +} + +/** + * @group Widget + * @group Report + * @group ReportWidgetFactory + * @group ReportWidgetFactoryTest + */ +class ReportWidgetFactoryTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var ReportWidgetFactory + */ + private $factory; + + public function setUp() + { + parent::setUp(); + + $this->factory = new ReportWidgetFactory(new GetBasicReport()); + } + + public function test_createContainerWidget_ShouldCreateAContainerBasedOnReportWithGivenId() + { + $config = $this->factory->createContainerWidget('myId'); + + $this->assertTrue($config instanceof WidgetContainerConfig); + $this->assertSame('myId', $config->getId()); + $this->assertSame('Goals_Goals', $config->getCategoryId()); + $this->assertSame('General_Overview', $config->getSubcategoryId()); + $this->assertSame(100 + 20, $config->getOrder()); + } + + public function test_createWidget_ShouldCreateAContainerBasedOnReportWithGivenId() + { + $config = $this->factory->createWidget(); + + $this->assertTrue($config instanceof ReportWidgetConfig); + $this->assertSame('Report_MyCustomReportName', $config->getName()); + $this->assertSame('Goals_Goals', $config->getCategoryId()); + $this->assertSame('General_Overview', $config->getSubcategoryId()); + $this->assertSame('graph', $config->getViewDataTable()); + $this->assertSame(100 + 20, $config->getOrder()); + $this->assertSame('TestPlugin', $config->getModule()); + $this->assertSame('getBasicReport', $config->getAction()); + + $this->assertSame(array( + 'viewDataTable' => 'graph', + 'module' => 'TestPlugin', + 'action' => 'getBasicReport', + 'idGoal' => '1' + ), $config->getParameters()); + } + + public function test_createCustomWidget_ShouldCreateAContainerBasedOnReportWithGivenId() + { + $config = $this->factory->createCustomWidget('customAction'); + + $this->assertTrue($config instanceof ReportWidgetConfig); + $this->assertSame('Report_MyCustomReportName', $config->getName()); + $this->assertSame('Goals_Goals', $config->getCategoryId()); + $this->assertSame('General_Overview', $config->getSubcategoryId()); + $this->assertNull($config->getViewDataTable()); + $this->assertSame(100 + 20, $config->getOrder()); + $this->assertSame('TestPlugin', $config->getModule()); + $this->assertSame('customAction', $config->getAction()); + + $this->assertSame(array( + 'module' => 'TestPlugin', + 'action' => 'customAction', + 'idGoal' => '1' + ), $config->getParameters()); + } + + +} diff --git a/tests/PHPUnit/Unit/Widget/WidgetConfigTest.php b/tests/PHPUnit/Unit/Widget/WidgetConfigTest.php new file mode 100644 index 0000000000..de6917ef0e --- /dev/null +++ b/tests/PHPUnit/Unit/Widget/WidgetConfigTest.php @@ -0,0 +1,224 @@ +config = new WidgetConfig(); + } + + public function test_name_set_get() + { + $this->config->setName('testName'); + + $this->assertSame('testName', $this->config->getName()); + } + + public function test_getName_shouldBeEmptyStringByDefault() + { + $this->assertSame('', $this->config->getName()); + } + + public function test_categoryId_set_get() + { + $this->config->setCategoryId('testCat'); + + $this->assertSame('testCat', $this->config->getCategoryId()); + } + + public function test_getCategoryId_shouldBeEmptyStringByDefault() + { + $this->assertSame('', $this->config->getCategoryId()); + } + + public function test_subcategoryId_set_get() + { + $this->config->setSubcategoryId('testsubcat'); + + $this->assertSame('testsubcat', $this->config->getSubcategoryId()); + } + + public function test_getSubcategoryId_shouldBeEmptyStringByDefault() + { + $this->assertSame('', $this->config->getSubcategoryId()); + } + + public function test_module_set_get() + { + $this->config->setModule('CoreHome'); + + $this->assertSame('CoreHome', $this->config->getModule()); + } + + public function test_getModule_shouldBeEmptyStringByDefault() + { + $this->assertSame('', $this->config->getModule()); + } + + public function test_action_set_get() + { + $this->config->setAction('get'); + + $this->assertSame('get', $this->config->getAction()); + } + + public function test_getAction_shouldBeEmptyStringByDefault() + { + $this->assertSame('', $this->config->getAction()); + } + + public function test_order_set_get() + { + $this->config->setOrder(99); + $this->assertSame(99, $this->config->getOrder()); + + $this->config->setOrder('98'); + $this->assertSame(98, $this->config->getOrder()); + } + + public function test_getOrder_shouldReturnADefaultValue() + { + $this->assertSame(99, $this->config->getOrder()); + } + + public function test_setMiddlewareParameters_set_get() + { + $this->config->setMiddlewareParameters(array( + 'module' => 'Goals', + 'action' => 'hasConversions' + )); + + $this->assertSame(array( + 'module' => 'Goals', + 'action' => 'hasConversions' + ), $this->config->getMiddlewareParameters()); + } + + public function test_getMiddlewareParameters_shouldReturnADefaultValue() + { + $this->assertSame(array(), $this->config->getMiddlewareParameters()); + } + + public function test_getParameters_ShouldAddModuleAndAction() + { + $this->setModuleAndAction(); + $this->assertSame(array('module' => 'CoreHome', 'action' => 'renderMe'), $this->config->getParameters()); + } + + public function test_getParameters_ShouldNotBePossibleToOverwriteModuleAndAction() + { + $this->setModuleAndAction(); + $this->config->setParameters(array('module' => 'Actions', 'action' => 'index')); + + $this->assertSame(array('module' => 'CoreHome', 'action' => 'renderMe'), $this->config->getParameters()); + } + + public function test_addParameters_ShouldAddMoreParams() + { + $this->setModuleAndAction(); + $this->config->addParameters(array('test' => '1')); // should be removed by setParameters + $this->config->addParameters(array('forceView' => '1')); + $this->config->addParameters(array('test' => '3')); + + $this->assertSame(array('module' => 'CoreHome', 'action' => 'renderMe', 'test' => '3', 'forceView' => '1'), $this->config->getParameters()); + } + + public function test_setParameters_ShouldOverwriteAnyExistingParameters() + { + $this->setModuleAndAction(); + $this->config->addParameters(array('test' => '1')); // should be removed by setParameters + $this->config->setParameters(array('forceView' => '1')); + + $this->assertSame(array('module' => 'CoreHome', 'action' => 'renderMe', 'forceView' => '1'), $this->config->getParameters()); + } + + public function test_shouldBeEnabledByDefault() + { + $this->assertTrue($this->config->isEnabled()); + } + + public function test_enable_disable() + { + $this->config->disable(); + $this->assertFalse($this->config->isEnabled()); + $this->config->enable(); + $this->assertTrue($this->config->isEnabled()); + } + + public function test_setIsEnabled() + { + $this->config->setIsEnabled(false); + $this->assertFalse($this->config->isEnabled()); + $this->config->setIsEnabled(true); + $this->assertTrue($this->config->isEnabled()); + } + + public function test_checkIsEnabled_shouldNotThrowException_IfEnabled() + { + $this->config->enable(); + $this->config->checkIsEnabled(); + } + + /** + * @expectedException \Exception + */ + public function test_checkIsEnabled_shouldThrowException_IfDisabled() + { + $this->config->disable(); + $this->config->checkIsEnabled(); + } + + public function test_shouldBeWidgetizable_ByDefault() + { + $this->assertTrue($this->config->isWidgetizeable()); + } + + public function test_widgetizeable() + { + $this->config->setIsNotWidgetizable(); + $this->assertFalse($this->config->isWidgetizeable()); + $this->config->setIsWidgetizable(); + $this->assertTrue($this->config->isWidgetizeable()); + } + + public function test_getUniqueId_withNoParameters() + { + $this->setModuleAndAction(); + $this->assertSame('widgetCoreHomerenderMe', $this->config->getUniqueId()); + } + + public function test_getUniqueId_withParameters() + { + $this->setModuleAndAction(); + $this->config->addParameters(array('viewDataTable' => 'table', 'forceView' => '1', 'mtest' => array('test'))); + $this->assertSame('widgetCoreHomerenderMeviewDataTabletableforceView1mtestArray', $this->config->getUniqueId()); + } + + private function setModuleAndAction() + { + $this->config->setModule('CoreHome'); + $this->config->setAction('renderMe'); + } + +} diff --git a/tests/PHPUnit/Unit/Widget/WidgetContainerConfigTest.php b/tests/PHPUnit/Unit/Widget/WidgetContainerConfigTest.php new file mode 100644 index 0000000000..7a2d3fedae --- /dev/null +++ b/tests/PHPUnit/Unit/Widget/WidgetContainerConfigTest.php @@ -0,0 +1,280 @@ +config = new WidgetContainerConfig(); + $this->config->setId($this->id); + } + + public function test_id_set_get() + { + $this->config->setId('testId'); + + $this->assertSame('testId', $this->config->getId()); + } + + public function test_name_set_get() + { + $this->config->setName('testName'); + + $this->assertSame('testName', $this->config->getName()); + } + + public function test_getName_shouldBeEmptyStringByDefault() + { + $this->assertSame('', $this->config->getName()); + } + + public function test_layout_set_get() + { + $this->config->setLayout('ByDimension'); + + $this->assertSame('ByDimension', $this->config->getLayout()); + } + + public function test_getLayout_shouldBeEmptyStringByDefault() + { + $this->assertSame('', $this->config->getLayout()); + } + + public function test_categoryId_set_get() + { + $this->config->setCategoryId('testCat'); + + $this->assertSame('testCat', $this->config->getCategoryId()); + } + + public function test_getCategoryId_shouldBeEmptyStringByDefault() + { + $this->assertSame('', $this->config->getCategoryId()); + } + + public function test_subcategoryId_set_get() + { + $this->config->setSubcategoryId('testsubcat'); + + $this->assertSame('testsubcat', $this->config->getSubcategoryId()); + } + + public function test_getSubcategoryId_shouldBeEmptyStringByDefault() + { + $this->assertSame('', $this->config->getSubcategoryId()); + } + + public function test_module_set_get() + { + $this->config->setModule('CoreHome'); + + $this->assertSame('CoreHome', $this->config->getModule()); + } + + public function test_getModule_shouldBeTheModuleToRenderItByDefault() + { + $this->assertSame('CoreHome', $this->config->getModule()); + } + + public function test_action_set_get() + { + $this->config->setAction('get'); + + $this->assertSame('get', $this->config->getAction()); + } + + public function test_getAction_shouldBeTheActionToRenderItByDefault() + { + $this->assertSame('renderWidgetContainer', $this->config->getAction()); + } + + public function test_order_set_get() + { + $this->config->setOrder(99); + $this->assertSame(99, $this->config->getOrder()); + + $this->config->setOrder('98'); + $this->assertSame(98, $this->config->getOrder()); + } + + public function test_getOrder_shouldReturnADefaultValue() + { + $this->assertSame(99, $this->config->getOrder()); + } + + public function test_setMiddlewareParameters_set_get() + { + $this->config->setMiddlewareParameters(array( + 'module' => 'Goals', + 'action' => 'hasConversions' + )); + + $this->assertSame(array( + 'module' => 'Goals', + 'action' => 'hasConversions' + ), $this->config->getMiddlewareParameters()); + } + + public function test_getMiddlewareParameters_shouldReturnADefaultValue() + { + $this->assertSame(array(), $this->config->getMiddlewareParameters()); + } + + public function test_getParameters_ShouldAddModuleAndAction() + { + $this->assertSame(array( + 'module' => 'CoreHome', + 'action' => 'renderWidgetContainer', + 'containerId' => $this->id + ), $this->config->getParameters()); + } + + public function test_getParameters_ShouldNotBePossibleToOverwriteModuleAndAction() + { + $this->config->setParameters(array('module' => 'Actions', 'action' => 'index', 'containerId' => 'test')); + + $this->assertSame(array( + 'module' => 'CoreHome', + 'action' => 'renderWidgetContainer', + 'containerId' => $this->id + ), $this->config->getParameters()); + } + + public function test_addParameters_ShouldAddMoreParams() + { + $this->config->addParameters(array('test' => '1')); // should be removed by setParameters + $this->config->addParameters(array('forceView' => '1')); + $this->config->addParameters(array('test' => '3')); + + $this->assertSame(array( + 'module' => 'CoreHome', + 'action' => 'renderWidgetContainer', + 'test' => '3', + 'forceView' => '1', + 'containerId' => $this->id + ), $this->config->getParameters()); + } + + public function test_setParameters_ShouldOverwriteAnyExistingParameters() + { + $this->config->addParameters(array('test' => '1')); // should be removed by setParameters + $this->config->setParameters(array('forceView' => '1')); + + $this->assertSame(array( + 'module' => 'CoreHome', + 'action' => 'renderWidgetContainer', + 'forceView' => '1', + 'containerId' => $this->id + ), $this->config->getParameters()); + } + + public function test_shouldBeEnabledByDefault() + { + $this->assertTrue($this->config->isEnabled()); + } + + public function test_enable_disable() + { + $this->config->disable(); + $this->assertFalse($this->config->isEnabled()); + $this->config->enable(); + $this->assertTrue($this->config->isEnabled()); + } + + public function test_setIsEnabled() + { + $this->config->setIsEnabled(false); + $this->assertFalse($this->config->isEnabled()); + $this->config->setIsEnabled(true); + $this->assertTrue($this->config->isEnabled()); + } + + public function test_checkIsEnabled_shouldNotThrowException_IfEnabled() + { + $this->config->enable(); + $this->config->checkIsEnabled(); + } + + /** + * @expectedException \Exception + */ + public function test_checkIsEnabled_shouldThrowException_IfDisabled() + { + $this->config->disable(); + $this->config->checkIsEnabled(); + } + + public function test_shouldNotBeWidgetizable_ByDefault() + { + $this->assertFalse($this->config->isWidgetizeable()); + } + + public function test_widgetizeable() + { + $this->config->setIsNotWidgetizable(); + $this->assertFalse($this->config->isWidgetizeable()); + $this->config->setIsWidgetizable(); + $this->assertTrue($this->config->isWidgetizeable()); + } + + public function test_getUniqueId_shouldIncludeContainerId() + { + $this->assertSame('widgetMyTestContainer', $this->config->getUniqueId()); + } + + public function test_getUniqueId_withParameters() + { + $this->config->addParameters(array('viewDataTable' => 'table', 'forceView' => '1', 'mtest' => array('test'))); + $this->assertSame('widgetMyTestContainerviewDataTabletableforceView1mtestArray', $this->config->getUniqueId()); + } + + public function test_getWidgetConfigs_shouldBeEmptyByDefault() + { + $this->assertSame(array(), $this->config->getWidgetConfigs()); + } + + public function test_widgetConfigs_shouldBeEmptyByDefault() + { + $this->config->addWidgetConfig($widget1 = $this->createWidgetConfig('widget1')); + $this->config->addWidgetConfig($widget2 = $this->createWidgetConfig('widget2')); + $this->config->addWidgetConfig($widget3 = $this->createWidgetConfig('widget3')); + $this->config->addWidgetConfig($widget4 = new WidgetContainerConfig()); // should be possible to add container to a container + $this->assertSame(array( + $widget1, + $widget2, + $widget3, + $widget4 + ), $this->config->getWidgetConfigs()); + } + + private function createWidgetConfig($widgetName) + { + $config = new WidgetConfig(); + $config->setName($widgetName); + + return $config; + } +} diff --git a/tests/PHPUnit/Unit/Widget/WidgetsListTest.php b/tests/PHPUnit/Unit/Widget/WidgetsListTest.php new file mode 100644 index 0000000000..050da65eaf --- /dev/null +++ b/tests/PHPUnit/Unit/Widget/WidgetsListTest.php @@ -0,0 +1,177 @@ +list = new WidgetsList(); + } + + public function test_getWidgetUniqueId_withoutParameters() + { + $id = WidgetsList::getWidgetUniqueId('CoreHome', 'render'); + $this->assertSame('widgetCoreHomerender', $id); + } + + public function test_getWidgetUniqueId_withParameters() + { + $id = WidgetsList::getWidgetUniqueId('CoreHome', 'render', array('test1' => 'value', 'key' => array('test'), 'test2' => '4k3k')); + $this->assertSame('widgetCoreHomerendertest1valuekeyArraytest24k3k', $id); + } + + public function test_getWidgetConfigs_shouldBeEmptyByDefault() + { + $this->assertSame(array(), $this->list->getWidgetConfigs()); + } + + public function test_addWidget_shouldAddAnyWidgetConfigs() + { + $this->list->addWidgetConfig($widget1 = $this->createWidget('widget1')); + $this->list->addWidgetConfig($widget2 = $this->createWidgetContainer('widget2')); + $this->list->addWidgetConfig($widget3 = $this->createWidget('widget3')); + + $this->assertSame(array($widget1, $widget2, $widget3), $this->list->getWidgetConfigs()); + } + + public function test_addWidgets_shouldAddAnyWidgetConfigs() + { + $this->list->addWidgetConfigs(array( + $widget1 = $this->createWidget('widget1'), + $widget2 = $this->createWidgetContainer('widget2'), + $widget3 = $this->createWidget('widget3'), + )); + + $this->assertSame(array($widget1, $widget2, $widget3), $this->list->getWidgetConfigs()); + } + + public function test_addToContainerWidget_shouldAddWidgetToContainerImmediately_IfContainerAlreadyExistsInList() + { + $this->list->addWidgetConfigs(array( + $widget1 = $this->createWidget('widget1'), + $widget2 = $this->createWidgetContainer('widget2')->setId('testId'), + $widget3 = $this->createWidget('widget3'), + )); + + $this->list->addToContainerWidget('testId', $widget4 = $this->createWidget('widget4')); + + $this->assertSame(array($widget4), $widget2->getWidgetConfigs()); + + // widget4 should not be added to this widgetConfigs + $this->assertSame(array($widget1, $widget2, $widget3), $this->list->getWidgetConfigs()); + } + + public function test_addToContainerWidget_shouldAddWidgetToContainerAsSoonAsContainerAdded_IfContainerNotAlreadyExistsInList() + { + $this->list->addToContainerWidget('testId', $widget4 = $this->createWidget('widget4')); + + $this->list->addWidgetConfigs(array( + $widget1 = $this->createWidget('widget1'), + $widget2 = $this->createWidgetContainer('widget2')->setId('testId'), + $widget3 = $this->createWidget('widget3'), + )); + + $this->assertSame(array($widget4), $widget2->getWidgetConfigs()); + + // widget4 should not be added to this widgetConfigs + $this->assertSame(array($widget1, $widget2, $widget3), $this->list->getWidgetConfigs()); + } + + /** + * @dataProvider getWidgetsToRemove + */ + public function test_remove($categoryId, $name, $expectedWidgetNamesInList) + { + $this->list->addWidgetConfigs(array( + $widget1 = $this->createWidget('widget1')->setCategoryId('Visits'), + $widget2 = $this->createWidgetContainer('widget2')->setCategoryId('Actions'), + $widget3 = $this->createWidget('widget3')->setCategoryId('Visits'), + )); + + $this->list->remove($categoryId, $name); + + $names = array(); + foreach ($this->list->getWidgetConfigs() as $config) { + $names[] = $config->getName(); + } + + $this->assertSame($expectedWidgetNamesInList, $names); + } + + public function getWidgetsToRemove() + { + return array( + array('Visits', false, array('widget2')), + array('Visits', 'widget3', array('widget1', 'widget2')), + array('Actions', false, array('widget1', 'widget3')), + array('Actions', 'widget2', array('widget1', 'widget3')), + array('Actions', 'notExist', array('widget1', 'widget2', 'widget3')), + array('NotExiSt', false, array('widget1', 'widget2', 'widget3')), + ); + } + + /** + * @dataProvider getWidgetsDefined + */ + public function test_isDefined($module, $action, $exists) + { + $this->list->addWidgetConfigs(array( + $widget1 = $this->createWidget('widget1')->setModule('CoreHome')->setAction('renderMe'), + $widget2 = $this->createWidgetContainer('widget2')->setModule('CoreHome')->setAction('renderContainer'), + $widget3 = $this->createWidget('widget3')->setModule('Actions')->setAction('index'), + )); + + $this->assertSame($exists, $this->list->isDefined($module, $action)); + } + + public function getWidgetsDefined() + { + return array( + array('CoreHome', 'renderMe', $isDefined = true), + array('CoreHome', 'renderContainer', $isDefined = true), + array('Actions', 'index', $isDefined = true), + array('Actions', 'renderMe', $isDefined = false), + array('AnyThiNg', 'renderMe', $isDefined = false), + array('CoreHome', 'index', $isDefined = false) + ); + } + + private function createWidget($name) + { + $config = new WidgetConfig(); + $config->setName($name); + + return $config; + } + + private function createWidgetContainer($name) + { + $config = new WidgetContainerConfig(); + $config->setName($name); + + return $config; + } + +} diff --git a/tests/UI/diff.png b/tests/UI/diff.png new file mode 100644 index 0000000000..910fca0df3 Binary files /dev/null and b/tests/UI/diff.png differ diff --git a/tests/UI/specs/DashboardManager_spec.js b/tests/UI/specs/DashboardManager_spec.js index 9ada832b83..77bfbcc9db 100644 --- a/tests/UI/specs/DashboardManager_spec.js +++ b/tests/UI/specs/DashboardManager_spec.js @@ -12,7 +12,9 @@ describe("DashboardManager", function () { this.timeout(0); var selectorToCapture = '.dashboard-manager'; - var url = "?module=CoreHome&action=index&idSite=1&period=day&date=2012-01-01"; + + var generalParams = 'idSite=1&period=day&date=2012-01-01'; + var url = '?module=CoreHome&action=index&' + generalParams + '#?' + generalParams + '&category=Dashboard_Dashboard&subcategory=5'; it("should load correctly", function (done) { expect.screenshot("loaded").to.be.captureSelector(selectorToCapture, function (page) { @@ -29,7 +31,7 @@ describe("DashboardManager", function () { it("should show widget for a category when category label hovered", function (done) { expect.screenshot("widget_list_shown").to.be.captureSelector(selectorToCapture, function (page) { page.mouseMove('.widgetpreview-categorylist>li:contains(Live!)'); // have to mouse move twice... otherwise Live! will just be highlighted - page.mouseMove('.widgetpreview-categorylist>li:contains(Visits Summary)'); + page.mouseMove('.widgetpreview-categorylist>li:contains(Visitors):first'); }, done); }); diff --git a/tests/UI/specs/Dashboard_spec.js b/tests/UI/specs/Dashboard_spec.js index e6918417d4..d02411d1a2 100644 --- a/tests/UI/specs/Dashboard_spec.js +++ b/tests/UI/specs/Dashboard_spec.js @@ -49,7 +49,7 @@ describe("Dashboard", function () { var layout = [ [ { - uniqueId: "widgetVisitsSummarygetEvolutionGraphcolumnsArray", + uniqueId: "widgetVisitsSummarygetEvolutionGraphforceView1viewDataTablegraphEvolution", parameters: {module: "VisitsSummary", action: "getEvolutionGraph", columns: "nb_visits"} } ], @@ -126,18 +126,20 @@ describe("Dashboard", function () { page.click('.dashboard-manager'); page.mouseMove('.widgetpreview-categorylist>li:contains(Live!)'); // have to mouse move twice... otherwise Live! will just be highlighted - page.mouseMove('.widgetpreview-categorylist>li:contains(Visits Summary)'); + page.mouseMove('.widgetpreview-categorylist>li:contains(Times):first'); - page.mouseMove('.widgetpreview-widgetlist>li:contains(Visits by Local Time)'); + page.mouseMove('.widgetpreview-widgetlist>li:contains(Visits per local time)'); - page.click('.widgetpreview-widgetlist>li:contains(Visits by Local Time)'); + page.click('.widgetpreview-widgetlist>li:contains(Visits per local time)'); }, done); }); it("should remove widget when remove widget icon is clicked", function (done) { expect.screenshot("widget_move").to.be.capture("widget_removed", function (page) { - page.mouseMove('#widgetVisitTimegetVisitInformationPerLocalTime .widgetTop'); - page.click('#widgetVisitTimegetVisitInformationPerLocalTime .button#close'); + var widget = '[id="widgetVisitTimegetVisitInformationPerLocalTimeviewDataTablegraphVerticalBar"]'; + + page.mouseMove(widget + ' .widgetTop'); + page.click(widget + ' .button#close'); page.click('.ui-dialog button>span:contains(Yes)'); page.mouseMove('.dashboard-manager'); }, done); @@ -148,7 +150,7 @@ describe("Dashboard", function () { page.click('.dashboard-manager'); page.click('li[data-action=showChangeDashboardLayoutDialog]'); page.click('div[layout=50-50]'); - page.click('.ui-dialog button>span:contains(Save)', 3000); + page.click('.ui-dialog button>span:contains(Save)'); }, done); }); @@ -168,11 +170,11 @@ describe("Dashboard", function () { page.click('.dashboard-manager'); page.click('li[data-action=copyDashboardToUser]'); page.evaluate(function () { - $('#copyDashboardName').val(''); + $('[id=copyDashboardName]:last').val(''); }); - page.sendKeys('#copyDashboardName', 'newdash'); + page.sendKeys('[id=copyDashboardName]:last', 'newdash'); page.evaluate(function () { - $('#copyDashboardUser').val('superUserLogin'); + $('[id=copyDashboardUser]:last').val('superUserLogin'); }); page.click('.ui-dialog button>span:contains(Ok)'); @@ -184,7 +186,7 @@ describe("Dashboard", function () { expect.screenshot("reset").to.be.capture(function (page) { page.click('.dashboard-manager'); page.click('li[data-action=resetDashboard]'); - page.click('.ui-dialog button>span:contains(Yes)', 10000); + page.click('.ui-dialog button>span:contains(Yes)', 4000); page.mouseMove('.dashboard-manager'); }, done); }); @@ -214,7 +216,7 @@ describe("Dashboard", function () { expect.screenshot("create_new").to.be.capture(function (page) { page.click('.dashboard-manager'); page.click('li[data-action=createDashboard]'); - page.sendKeys('#createDashboardName', 'newdash2'); + page.sendKeys('#createDashboardName:visible', 'newdash2'); page.click('.ui-dialog[aria-describedby=createDashboardConfirm] button>span:contains(Yes)'); }, done); }); diff --git a/tests/UI/specs/Menus_spec.js b/tests/UI/specs/Menus_spec.js index d3fe6720c0..a79c282ce7 100644 --- a/tests/UI/specs/Menus_spec.js +++ b/tests/UI/specs/Menus_spec.js @@ -17,19 +17,32 @@ describe("Menus", function () { // main menu tests it('should load the main reporting menu correctly', function (done) { expect.screenshot('mainmenu_loaded').to.be.captureSelector('.Menu--dashboard,.nav_sep', function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=Actions&action=menuGetPageUrls"); + page.load("?" + urlBase + "#?" + generalParams + "&category=General_Actions&subcategory=General_Pages"); }, done); }); it('should change the menu when a upper menu item is clicked in the main menu', function (done) { expect.screenshot('mainmenu_upper_clicked').to.be.captureSelector('.Menu--dashboard,.nav_sep', function (page) { - page.click('.Menu-tabList > li:eq(1) > a'); + page.click('.menuItem:contains(Visitors)'); }, done); }); it('should change the menu when a lower menu item is clicked in the main menu', function (done) { expect.screenshot('mainmenu_lower_clicked').to.be.captureSelector('.Menu--dashboard,.nav_sep', function (page) { - page.click('.Menu-tabList > li:eq(1) > ul > li:eq(1) > a'); + page.click('.menuItem:contains(Visitor Log)'); + }, done); + }); + + // user menu tests + it('should load the user reporting menu correctly', function (done) { + expect.screenshot('user_loaded').to.be.captureSelector('.Menu--admin', function (page) { + page.load("?" + generalParams + "&module=UsersManager&action=userSettings"); + }, done); + }); + + it('should change the user page correctly when a user menu item is clicked', function (done) { + expect.screenshot('user_changed').to.be.captureSelector('.Menu--admin', function (page) { + page.click('.Menu--admin a:contains(API)'); }, done); }); @@ -58,4 +71,4 @@ describe("Menus", function () { page.click('.Menu--admin a:contains(Websites)'); }, done); }); -}); \ No newline at end of file +}); diff --git a/tests/UI/specs/Overlay_spec.js b/tests/UI/specs/Overlay_spec.js index 07068e96f5..5fb74621f5 100644 --- a/tests/UI/specs/Overlay_spec.js +++ b/tests/UI/specs/Overlay_spec.js @@ -20,7 +20,7 @@ describe("Overlay", function () { } before(function (done) { - url = "?module=Overlay&period=year&date=today&idSite=3#l=" + encodeURIComponent(testEnvironment.overlayUrl).replace(/[%]/g, "$"); + url = "?module=Overlay&period=year&date=today&idSite=3#?l=" + encodeURIComponent(testEnvironment.overlayUrl).replace(/[%]/g, "$"); testEnvironment.callApi("SitesManager.addSiteAliasUrls", {idSite: 3, urls: [config.piwikUrl]}, done); }); diff --git a/tests/UI/specs/PeriodSelector_spec.js b/tests/UI/specs/PeriodSelector_spec.js index c070f4beb5..4706498ccb 100644 --- a/tests/UI/specs/PeriodSelector_spec.js +++ b/tests/UI/specs/PeriodSelector_spec.js @@ -10,7 +10,8 @@ describe("PeriodSelector", function () { this.timeout(0); - var url = "?module=CoreHome&action=index&idSite=1&period=day&date=2012-01-01"; + var generalParams = 'idSite=1&period=day&date=2012-01-01'; + var url = '?module=CoreHome&action=index&' + generalParams + '#?' + generalParams + '&category=General_Actions&subcategory=General_Pages'; it("should load correctly", function (done) { expect.screenshot("loaded").to.be.captureSelector('#periodString', function (page) { diff --git a/tests/UI/specs/PivotByDimension_spec.js b/tests/UI/specs/PivotByDimension_spec.js index f1899f3485..938d298ef5 100644 --- a/tests/UI/specs/PivotByDimension_spec.js +++ b/tests/UI/specs/PivotByDimension_spec.js @@ -10,9 +10,9 @@ describe("PivotByDimension", function () { this.timeout(0); - var eventsUrl = "?module=CoreHome&action=index&idSite=1&period=year&date=2012-08-09#/idSite=1&period=year&date=2012-08-09&module=Events&action=index", - actionsUrl = "?module=CoreHome&action=index&idSite=1&period=year&date=2012-08-09#/idSite=1&period=year&date=2012-08-09&module=Actions&action=menuGetPageUrls", - cvarsUrl = "?module=CoreHome&action=index&idSite=1&period=year&date=2012-08-09#/idSite=1&period=year&date=2012-08-09&module=CustomVariables&action=menuGetCustomVariables" + var eventsUrl = "?module=CoreHome&action=index&idSite=1&period=year&date=2012-08-09#?idSite=1&period=year&date=2012-08-09&category=General_Actions&subcategory=Events_Events", + actionsUrl = "?module=CoreHome&action=index&idSite=1&period=year&date=2012-08-09#?idSite=1&period=year&date=2012-08-09&category=General_Actions&subcategory=General_Pages", + cvarsUrl = "?module=CoreHome&action=index&idSite=1&period=year&date=2012-08-09#?idSite=1&period=year&date=2012-08-09&category=General_Visitors&subcategory=CustomVariables_CustomVariables" ; it("should pivot a report correctly when the pivot cog option is selected", function (done) { diff --git a/tests/UI/specs/ReportExporting_spec.js b/tests/UI/specs/ReportExporting_spec.js index fc223edfcc..992dd18b4f 100644 --- a/tests/UI/specs/ReportExporting_spec.js +++ b/tests/UI/specs/ReportExporting_spec.js @@ -11,8 +11,8 @@ describe("ReportExporting", function () { this.timeout(0); var baseUrl = "?module=Widgetize&action=iframe&idSite=1&period=year&date=2012-08-09&isFooterExpandedInDashboard=1", - referrersGetWebsitesUrl = baseUrl + "&moduleToWidgetize=Referrers&actionToWidgetize=getWebsites&viewDataTable=table&filter_limit=5", - visitsSummaryGetUrl = baseUrl + "&moduleToWidgetize=VisitsSummary&actionToWidgetize=get&viewDataTable=graphEvolution"; + referrersGetWebsitesUrl = baseUrl + "&moduleToWidgetize=Referrers&actionToWidgetize=getWebsites&filter_limit=5", + visitsSummaryGetUrl = baseUrl + "&moduleToWidgetize=VisitsSummary&actionToWidgetize=get&forceView=1&viewDataTable=graphEvolution"; function normalReportTest(format) { it("should export a normal report correctly when the " + format + " export link is clicked", function (done) { diff --git a/tests/UI/specs/SegmentSelectorEditor_spec.js b/tests/UI/specs/SegmentSelectorEditor_spec.js index 01066c3bbf..f00a9e87d5 100644 --- a/tests/UI/specs/SegmentSelectorEditor_spec.js +++ b/tests/UI/specs/SegmentSelectorEditor_spec.js @@ -12,7 +12,8 @@ describe("SegmentSelectorEditorTest", function () { this.timeout(0); - var url = "?module=CoreHome&action=index&idSite=1&period=year&date=2012-08-09"; + var generalParams = 'idSite=1&period=year&date=2012-08-09'; + var url = '?module=CoreHome&action=index&' + generalParams + '#?' + generalParams + '&category=General_Actions&subcategory=General_Pages'; it("should load correctly", function (done) { expect.screenshot("0_initial").to.be.captureSelector(selectorsToCapture, function (page) { @@ -149,7 +150,9 @@ describe("SegmentSelectorEditorTest", function () { }); }); - page.click('button.saveAndApply'); + page.evaluate(function () { + $('button.saveAndApply').click(); + }); page.click('.segmentationContainer'); }, done); diff --git a/tests/UI/specs/Transitions_spec.js b/tests/UI/specs/Transitions_spec.js index 246c4bb3da..dcbc87901a 100644 --- a/tests/UI/specs/Transitions_spec.js +++ b/tests/UI/specs/Transitions_spec.js @@ -16,7 +16,7 @@ describe("Transitions", function () { it('should load the transitions popup correctly for the page titles report', function (done) { expect.screenshot('transitions_popup_titles').to.be.captureSelector('.ui-dialog', function (page) { - page.load("?" + urlBase + "#/" + generalParams + "&module=Actions&action=menuGetPageTitles"); + page.load("?" + urlBase + "#?" + generalParams + "&category=General_Actions&subcategory=Actions_SubmenuPageTitles"); page.mouseMove('div.dataTable tbody tr:eq(2)'); page.mouseMove('a.actionTransitions:visible'); // necessary to get popover to display @@ -26,7 +26,7 @@ describe("Transitions", function () { it('should load the transitions popup correctly for the page urls report', function (done) { expect.screenshot('transitions_popup_urls').to.be.captureSelector('.ui-dialog', function (page) { - page.load("?" + urlBase + "#/" + generalParams + "&module=Actions&action=menuGetPageUrls&" + page.load("?" + urlBase + "#?" + generalParams + "&category=General_Actions&subcategory=General_Pages&" + "popover=RowAction$3ATransitions$3Aurl$3Ahttp$3A$2F$2Fpiwik.net$2Fdocs$2Fmanage-websites$2F"); }, done); }); diff --git a/tests/UI/specs/UIIntegration_spec.js b/tests/UI/specs/UIIntegration_spec.js index d1f7ac80ae..c58f50af4f 100644 --- a/tests/UI/specs/UIIntegration_spec.js +++ b/tests/UI/specs/UIIntegration_spec.js @@ -44,7 +44,7 @@ describe("UIIntegrationTest", function () { // TODO: Rename to Piwik? // dashboard tests it("should load dashboard1 correctly", function (done) { expect.screenshot("dashboard1").to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=Dashboard&action=embeddedIndex&idDashboard=1"); + page.load("?" + urlBase + "#?" + generalParams + "&category=Dashboard_Dashboard&subcategory=1"); page.evaluate(function () { // Prevent random sizing error eg. http://builds-artifacts.piwik.org/ui-tests.master/2301.1/screenshot-diffs/diffviewer.html @@ -55,26 +55,26 @@ describe("UIIntegrationTest", function () { // TODO: Rename to Piwik? it("should load dashboard2 correctly", function (done) { expect.screenshot("dashboard2").to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=Dashboard&action=embeddedIndex&idDashboard=2"); + page.load("?" + urlBase + "#?" + generalParams + "&category=Dashboard_Dashboard&subcategory=2"); }, done); }); it("should load dashboard3 correctly", function (done) { expect.screenshot("dashboard3").to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=Dashboard&action=embeddedIndex&idDashboard=3"); + page.load("?" + urlBase + "#?" + generalParams + "&category=Dashboard_Dashboard&subcategory=3"); }, done); }); it("should load dashboard4 correctly", function (done) { expect.screenshot("dashboard4").to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=Dashboard&action=embeddedIndex&idDashboard=4"); + page.load("?" + urlBase + "#?" + generalParams + "&category=Dashboard_Dashboard&subcategory=4"); }, done); }); it("should display dashboard correctly on a mobile phone", function (done) { expect.screenshot("dashboard5_mobile").to.be.capture(function (page) { // capture with menu page.setViewportSize(480, 320); - page.load("?" + urlBase + "#" + generalParams + "&module=Dashboard&action=embeddedIndex&idDashboard=5"); + page.load("?" + urlBase + "#?" + generalParams + "&category=Dashboard_Dashboard&subcategory=5"); }, done); }); @@ -82,55 +82,55 @@ describe("UIIntegrationTest", function () { // TODO: Rename to Piwik? it('should load visitors > overview page correctly', function (done) { expect.screenshot("visitors_overview").to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { // use columns query param to make sure columns works when supplied in URL fragment - page.load("?" + urlBase + "#" + generalParams + "&module=VisitsSummary&action=index&columns=nb_visits,nb_actions"); + page.load("?" + urlBase + "#?" + generalParams + "&category=General_Visitors&subcategory=General_Overview&columns=nb_visits,nb_actions"); }, done); }); it('should load visitors > visitor log page correctly', function (done) { expect.screenshot("visitors_visitorlog").to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=Live&action=indexVisitorLog"); + page.load("?" + urlBase + "#?" + generalParams + "&category=General_Visitors&subcategory=Live_VisitorLog"); }, done); }); it('should load the visitors > devices page correctly', function (done) { expect.screenshot("visitors_devices").to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=DevicesDetection&action=index"); + page.load("?" + urlBase + "#?" + generalParams + "&category=General_Visitors&subcategory=DevicesDetection_Devices"); }, done); }); it('should load visitors > locations & provider page correctly', function (done) { expect.screenshot("visitors_locations_provider").to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=UserCountry&action=index"); + page.load("?" + urlBase + "#?" + generalParams + "&category=General_Visitors&subcategory=UserCountry_SubmenuLocations"); }, done); }); it('should load the visitors > software page correctly', function (done) { expect.screenshot("visitors_software").to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=DevicesDetection&action=software"); + page.load("?" + urlBase + "#?" + generalParams + "&category=General_Visitors&subcategory=DevicesDetection_Software"); }, done); }); it('should load the visitors > times page correctly', function (done) { expect.screenshot("visitors_times").to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=VisitTime&action=index"); + page.load("?" + urlBase + "#?" + generalParams + "&category=General_Visitors&subcategory=VisitTime_SubmenuTimes"); }, done); }); it('should load the visitors > engagement page correctly', function (done) { expect.screenshot("visitors_engagement").to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=VisitFrequency&action=index"); + page.load("?" + urlBase + "#?" + generalParams + "&category=General_Visitors&subcategory=VisitorInterest_Engagement"); }, done); }); it('should load the visitors > custom variables page correctly', function (done) { expect.screenshot('visitors_custom_vars').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=CustomVariables&action=menuGetCustomVariables"); + page.load("?" + urlBase + "#?" + generalParams + "&category=General_Visitors&subcategory=CustomVariables_CustomVariables"); }, done); }); it('should load the visitors > real-time map page correctly', function (done) { expect.screenshot('visitors_realtime_map').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { - page.load("?" + urlBase + "#" + idSite2Params + "&module=UserCountryMap&action=realtimeWorldMap" + page.load("?" + urlBase + "#?" + idSite2Params + "&category=General_Visitors&subcategory=UserCountryMap_RealTimeMap" + "&showDateTime=0&realtimeWindow=last2&changeVisitAlpha=0&enableAnimation=0&doNotRefreshVisits=1" + "&removeOldVisits=0"); }, done); @@ -139,49 +139,49 @@ describe("UIIntegrationTest", function () { // TODO: Rename to Piwik? // actions pages it('should load the actions > pages page correctly', function (done) { expect.screenshot('actions_pages').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=Actions&action=menuGetPageUrls"); + page.load("?" + urlBase + "#?" + generalParams + "&category=General_Actions&subcategory=General_Pages"); }, done); }); it('should load the actions > entry pages page correctly', function (done) { expect.screenshot('actions_entry_pages').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=Actions&action=menuGetEntryPageUrls"); + page.load("?" + urlBase + "#?" + generalParams + "&category=General_Actions&subcategory=Actions_SubmenuPagesEntry"); }, done); }); it('should load the actions > exit pages page correctly', function (done) { expect.screenshot('actions_exit_pages').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=Actions&action=menuGetExitPageUrls"); + page.load("?" + urlBase + "#?" + generalParams + "&category=General_Actions&subcategory=Actions_SubmenuPagesExit"); }, done); }); it('should load the actions > page titles page correctly', function (done) { expect.screenshot('actions_page_titles').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=Actions&action=menuGetPageTitles"); + page.load("?" + urlBase + "#?" + generalParams + "&category=General_Actions&subcategory=Actions_SubmenuPageTitles"); }, done); }); it('should load the actions > site search page correctly', function (done) { expect.screenshot('actions_site_search').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=Actions&action=indexSiteSearch"); + page.load("?" + urlBase + "#?" + generalParams + "&category=General_Actions&subcategory=Actions_SubmenuSitesearch"); }, done); }); it('should load the actions > outlinks page correctly', function (done) { expect.screenshot('actions_outlinks').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=Actions&action=menuGetOutlinks"); + page.load("?" + urlBase + "#?" + generalParams + "&category=General_Actions&subcategory=General_Outlinks"); }, done); }); it('should load the actions > downloads page correctly', function (done) { expect.screenshot('actions_downloads').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=Actions&action=menuGetDownloads"); + page.load("?" + urlBase + "#?" + generalParams + "&category=General_Actions&subcategory=General_Downloads"); }, done); }); it('should load the actions > contents page correctly', function (done) { expect.screenshot('actions_contents').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=Contents&action=index&period=day&date=2012-01-01"); + page.load("?" + urlBase + "#?" + generalParams + "&category=General_Actions&subcategory=Contents_Contents&period=day&date=2012-01-01"); }, done); }); @@ -206,108 +206,102 @@ describe("UIIntegrationTest", function () { // TODO: Rename to Piwik? // referrers pages it('should load the referrers > overview page correctly', function (done) { expect.screenshot('referrers_overview').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=Referrers&action=index"); + page.load("?" + urlBase + "#?" + generalParams + "&category=Referrers_Referrers&subcategory=General_Overview"); }, done); }); // referrers pages it('should load the referrers > overview page correctly', function (done) { expect.screenshot('referrers_allreferrers').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=Referrers&action=allReferrers"); + page.load("?" + urlBase + "#?" + generalParams + "&category=Referrers_Referrers&subcategory=Referrers_WidgetGetAll"); }, done); }); it('should load the referrers > search engines & keywords page correctly', function (done) { expect.screenshot('referrers_search_engines_keywords').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=Referrers&action=getSearchEnginesAndKeywords"); + page.load("?" + urlBase + "#?" + generalParams + "&category=Referrers_Referrers&subcategory=Referrers_SubmenuSearchEngines"); }, done); }); it('should load the referrers > websites & social page correctly', function (done) { expect.screenshot('referrers_websites_social').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=Referrers&action=indexWebsites"); + page.load("?" + urlBase + "#?" + generalParams + "&category=Referrers_Referrers&subcategory=Referrers_SubmenuWebsites"); }, done); }); it('should load the referrers > campaigns page correctly', function (done) { expect.screenshot('referrers_campaigns').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=Referrers&action=menuGetCampaigns"); + page.load("?" + urlBase + "#?" + generalParams + "&category=Referrers_Referrers&subcategory=Referrers_Campaigns"); }, done); }); // goals pages - it('should load the goals > ecommerce page correctly', function (done) { - expect.screenshot('goals_ecommerce').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=Ecommerce&action=ecommerceReport&idGoal=ecommerceOrder"); - }, done); - }); - it('should load the goals > overview page correctly', function (done) { expect.screenshot('goals_overview').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { - page.load( "?" + urlBase + "#" + generalParams + "&module=Goals&action=index"); + page.load( "?" + urlBase + "#?" + generalParams + "&category=Goals_Goals&subcategory=General_Overview"); }, done); }); it('should load the goals > management page correctly', function (done) { - expect.screenshot('goals_manage').to.be.captureSelector('.centerLargeDiv,.top_bar_sites_selector,.entityContainer', function (page) { - page.load( "?" + generalParams + "&module=Goals&action=manage"); + expect.screenshot('goals_manage').to.be.captureSelector('#content,.top_bar_sites_selector,.entityContainer', function (page) { + page.load("?" + generalParams + "&module=Goals&action=manage"); page.wait(200); }, done); }); it('should load the goals > single goal page correctly', function (done) { expect.screenshot('goals_individual_goal').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=Goals&action=goalReport&idGoal=1"); + page.load("?" + urlBase + "#?" + generalParams + "&category=Goals_Goals&subcategory=1"); }, done); }); // one page w/ segment it('should load the visitors > overview page correctly when a segment is specified', function (done) { expect.screenshot('visitors_overview_segment').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=VisitsSummary&action=index&segment=" + segment); + page.load("?" + urlBase + "#?" + generalParams + "&category=General_Visitors&subcategory=General_Overview&segment=" + segment); }, done); }); // example ui pages it('should load the example ui > dataTables page correctly', function (done) { expect.screenshot('exampleui_dataTables').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=ExampleUI&action=dataTables"); + page.load("?" + urlBase + "#?" + generalParams + "&category=ExampleUI_UiFramework&subcategory=ExampleUI_GetTemperaturesDataTable"); }, done); }); it('should load the example ui > barGraph page correctly', function (done) { expect.screenshot('exampleui_barGraph').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=ExampleUI&action=barGraph"); + page.load("?" + urlBase + "#?" + generalParams + "&category=ExampleUI_UiFramework&subcategory=Bar%20graph"); }, done); }); it('should load the example ui > pieGraph page correctly', function (done) { expect.screenshot('exampleui_pieGraph').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=ExampleUI&action=pieGraph"); + page.load("?" + urlBase + "#?" + generalParams + "&category=ExampleUI_UiFramework&subcategory=Pie%20graph"); }, done); }); it('should load the example ui > tagClouds page correctly', function (done) { expect.screenshot('exampleui_tagClouds').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=ExampleUI&action=tagClouds"); + page.load("?" + urlBase + "#?" + generalParams + "&category=ExampleUI_UiFramework&subcategory=Tag%20clouds"); }, done); }); it('should load the example ui > sparklines page correctly', function (done) { expect.screenshot('exampleui_sparklines').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=ExampleUI&action=sparklines"); + page.load("?" + urlBase + "#?" + generalParams + "&category=ExampleUI_UiFramework&subcategory=Sparklines"); }, done); }); it('should load the example ui > evolution graph page correctly', function (done) { expect.screenshot('exampleui_evolutionGraph').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=ExampleUI&action=evolutionGraph"); + page.load("?" + urlBase + "#?" + generalParams + "&category=ExampleUI_UiFramework&subcategory=Evolution%20Graph"); }, done); }); it('should load the example ui > treemap page correctly', function (done) { expect.screenshot('exampleui_treemap').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=ExampleUI&action=treemap"); + page.load("?" + urlBase + "#?" + generalParams + "&category=ExampleUI_UiFramework&subcategory=Treemap"); page.wait(2000); }, done); }); @@ -343,32 +337,32 @@ describe("UIIntegrationTest", function () { // TODO: Rename to Piwik? it('should not display API response in the content', function (done) { expect.screenshot('menu_apidisallowed').to.be.captureSelector('#content', function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=API&action=SitesManager.getImageTrackingCode"); + page.load("?" + urlBase + "#?" + generalParams + "&module=API&action=SitesManager.getImageTrackingCode"); }, done); }); // Ecommerce it('should load the ecommerce overview page', function (done) { expect.screenshot('ecommerce_overview').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=Ecommerce&action=ecommerceReport&idGoal=ecommerceOrder"); + page.load("?" + urlBase + "#?" + generalParams + "&category=Goals_Ecommerce&subcategory=General_Overview"); }, done); }); it('should load the ecommerce log page', function (done) { expect.screenshot('ecommerce_log').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=Ecommerce&action=ecommerceLogReport"); + page.load("?" + urlBase + "#?" + generalParams + "&category=Goals_Ecommerce&subcategory=Goals_EcommerceLog"); }, done); }); it('should load the ecommerce products page', function (done) { expect.screenshot('ecommerce_products').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=Ecommerce&action=products&idGoal=ecommerceOrder"); + page.load("?" + urlBase + "#?" + generalParams + "&category=Goals_Ecommerce&subcategory=Goals_Products"); }, done); }); it('should load the ecommerce sales page', function (done) { expect.screenshot('ecommerce_sales').to.be.captureSelector('.pageWrap,.expandDataTableFooterDrawer', function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=Ecommerce&action=sales&idGoal=ecommerceOrder"); + page.load("?" + urlBase + "#?" + generalParams + "&category=Goals_Ecommerce&subcategory=Ecommerce_Sales"); }, done); }); @@ -532,8 +526,8 @@ describe("UIIntegrationTest", function () { // TODO: Rename to Piwik? it('should load the widgets listing page correctly', function (done) { expect.screenshot('widgets_listing').to.be.captureSelector('#content', function (page) { page.load("?" + generalParams + "&module=Widgetize&action=index"); - page.mouseMove('.widgetpreview-categorylist>li:contains(Visits Summary)'); - page.mouseMove('li[uniqueid=widgetVisitsSummarygetEvolutionGraphcolumnsArray]'); + page.mouseMove('.widgetpreview-categorylist>li:contains(Visitors)'); + page.mouseMove('li[uniqueid="widgetVisitsSummarygetEvolutionGraphforceView1viewDataTablegraphEvolution"]'); }, done); }); @@ -576,7 +570,7 @@ describe("UIIntegrationTest", function () { // TODO: Rename to Piwik? // date range clicked it('should reload to the correct date when a date range is selected in the period selector', function (done) { expect.screenshot('period_select_date_range_click').to.be.capture(function (page) { - page.load("?" + urlBase + "#" + generalParams + "&module=VisitTime&action=index"); + page.load("?" + urlBase + "#?" + generalParams + "&category=General_Visitors&subcategory=VisitTime_SubmenuTimes"); page.evaluate(function () { $(document).ready(function () { $('#date').click(); @@ -629,7 +623,7 @@ describe("UIIntegrationTest", function () { // TODO: Rename to Piwik? }); it('should load the segmented visitor log correctly when a segment is selected', function (done) { - var url = "?module=CoreHome&action=index&idSite=1&period=year&date=2012-01-13#?module=CustomVariables&action=menuGetCustomVariables&idSite=1&period=year&date=2012-01-13"; + var url = "?module=CoreHome&action=index&idSite=1&period=year&date=2012-01-13#?category=General_Visitors&subcategory=CustomVariables_CustomVariables&idSite=1&period=year&date=2012-01-13"; expect.page(url).contains('.ui-dialog > .ui-dialog-content > div.dataTableVizVisitorLog:visible', 'segmented_visitorlog', function (page) { page.click('.segmentationTitle'); page.click('.segname:contains(From Europe)'); @@ -639,4 +633,4 @@ describe("UIIntegrationTest", function () { // TODO: Rename to Piwik? page.click('a.actionSegmentVisitorLog:visible'); }, done); }); -}); \ No newline at end of file +}); diff --git a/tests/lib/screenshot-testing/support/chai-extras.js b/tests/lib/screenshot-testing/support/chai-extras.js index f07651053d..05cabf82da 100644 --- a/tests/lib/screenshot-testing/support/chai-extras.js +++ b/tests/lib/screenshot-testing/support/chai-extras.js @@ -74,7 +74,7 @@ function capture(screenName, compareAgainst, selector, pageSetupFn, comparisonTh processedScreenshotPath = getProcessedScreenshotPath(screenName); - screenshotDiffDir = path.join(options['store-in-ui-tests-repo'] ? uiTestsDir : dirsBase, config.screenshotDiffDir); + screenshotDiffDir = path.join(options['store-in-ui-tests-repo'] ? uiTestsDir : dirsBase, config.screenshotDiffDir); if (!fs.isDirectory(screenshotDiffDir)) { fs.makeTree(screenshotDiffDir); @@ -168,7 +168,7 @@ function capture(screenName, compareAgainst, selector, pageSetupFn, comparisonTh } else { testFailure += "(image magick error: " + numPxDifference; } - + testFailure += ")\n"; } } @@ -376,7 +376,7 @@ chai.Assertion.addChainableMethod('contains', function () { stack += indent + "View the captured screenshot at '" + capturePath + "'."; } else { stack += indent + "NOTE: No screenshot name was supplied to this '.contains(' assertion. If the second argument is a screenshot name, " - + "the screenshot will be saved so you can debug this failure."; + + "the screenshot will be saved so you can debug this failure."; } stack += getPageLogsString(pageRenderer.pageLogs, indent); @@ -404,4 +404,4 @@ chai.Assertion.addChainableMethod('pageContents', function (pageSetupFn, done) { var compareAgainst = this.__flags['object']; compareContents(compareAgainst, pageSetupFn, done); -}); +}); \ No newline at end of file diff --git a/tests/lib/screenshot-testing/support/page-renderer.js b/tests/lib/screenshot-testing/support/page-renderer.js index 3a0ef301d0..70231c3ca7 100644 --- a/tests/lib/screenshot-testing/support/page-renderer.js +++ b/tests/lib/screenshot-testing/support/page-renderer.js @@ -415,11 +415,11 @@ PageRenderer.prototype.capture = function (outputPath, callback, selector) { callback(); }, timeInMsToWaitForReRenderToFinish); - + } else { callback(); } - + } catch (e) { self.webpage.clipRect = previousClipRect; -- cgit v1.2.3