PageRenderTime 54ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/plugins/Referrers/Controller.php

https://github.com/CodeYellowBV/piwik
PHP | 546 lines | 389 code | 77 blank | 80 comment | 30 complexity | bc4f0fbac6fd128847ea64e0ff05e5b5 MD5 | raw file
Possible License(s): LGPL-3.0, JSON, MIT, GPL-3.0, LGPL-2.1, GPL-2.0, AGPL-1.0, BSD-2-Clause, BSD-3-Clause
  1. <?php
  2. /**
  3. * Piwik - free/libre analytics platform
  4. *
  5. * @link http://piwik.org
  6. * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
  7. *
  8. */
  9. namespace Piwik\Plugins\Referrers;
  10. use Piwik\API\Request;
  11. use Piwik\Common;
  12. use Piwik\DataTable\Map;
  13. use Piwik\Metrics;
  14. use Piwik\Period\Range;
  15. use Piwik\Piwik;
  16. use Piwik\SettingsPiwik;
  17. use Piwik\View;
  18. /**
  19. *
  20. */
  21. class Controller extends \Piwik\Plugin\Controller
  22. {
  23. public function index()
  24. {
  25. $view = new View('@Referrers/index');
  26. $view->graphEvolutionReferrers = $this->getEvolutionGraph(Common::REFERRER_TYPE_DIRECT_ENTRY, array(), array('nb_visits'));
  27. $view->nameGraphEvolutionReferrers = 'Referrers.getEvolutionGraph';
  28. // building the referrers summary report
  29. $view->dataTableReferrerType = $this->getReferrerType(true);
  30. $nameValues = $this->getReferrersVisitorsByType();
  31. $totalVisits = array_sum($nameValues);
  32. foreach ($nameValues as $name => $value) {
  33. $view->$name = $value;
  34. // calculate percent of total, if there were any visits
  35. if ($value != 0
  36. && $totalVisits != 0
  37. ) {
  38. $percentName = $name . 'Percent';
  39. $view->$percentName = round(($value / $totalVisits) * 100, 0);
  40. }
  41. }
  42. // set distinct metrics
  43. $distinctMetrics = $this->getDistinctReferrersMetrics();
  44. foreach ($distinctMetrics as $name => $value) {
  45. $view->$name = $value;
  46. }
  47. // calculate evolution for visit metrics & distinct metrics
  48. list($lastPeriodDate, $ignore) = Range::getLastDate();
  49. if ($lastPeriodDate !== false) {
  50. $date = Common::getRequestVar('date');
  51. $period = Common::getRequestVar('period');
  52. $prettyDate = self::getPrettyDate($date, $period);
  53. $prettyLastPeriodDate = self::getPrettyDate($lastPeriodDate, $period);
  54. // visit metrics
  55. $previousValues = $this->getReferrersVisitorsByType($lastPeriodDate);
  56. $this->addEvolutionPropertiesToView($view, $prettyDate, $nameValues, $prettyLastPeriodDate, $previousValues);
  57. // distinct metrics
  58. $previousValues = $this->getDistinctReferrersMetrics($lastPeriodDate);
  59. $this->addEvolutionPropertiesToView($view, $prettyDate, $distinctMetrics, $prettyLastPeriodDate, $previousValues);
  60. }
  61. // sparkline for the historical data of the above values
  62. $view->urlSparklineSearchEngines = $this->getReferrerUrlSparkline(Common::REFERRER_TYPE_SEARCH_ENGINE);
  63. $view->urlSparklineDirectEntry = $this->getReferrerUrlSparkline(Common::REFERRER_TYPE_DIRECT_ENTRY);
  64. $view->urlSparklineWebsites = $this->getReferrerUrlSparkline(Common::REFERRER_TYPE_WEBSITE);
  65. $view->urlSparklineCampaigns = $this->getReferrerUrlSparkline(Common::REFERRER_TYPE_CAMPAIGN);
  66. // sparklines for the evolution of the distinct keywords count/websites count/ etc
  67. $view->urlSparklineDistinctSearchEngines = $this->getUrlSparkline('getLastDistinctSearchEnginesGraph');
  68. $view->urlSparklineDistinctKeywords = $this->getUrlSparkline('getLastDistinctKeywordsGraph');
  69. $view->urlSparklineDistinctWebsites = $this->getUrlSparkline('getLastDistinctWebsitesGraph');
  70. $view->urlSparklineDistinctCampaigns = $this->getUrlSparkline('getLastDistinctCampaignsGraph');
  71. $view->totalVisits = $totalVisits;
  72. $view->referrersReportsByDimension = $this->getReferrersReportsByDimensionView($totalVisits);
  73. return $view->render();
  74. }
  75. /**
  76. * Returns HTML for the Referrers Overview page that categorizes Referrer reports
  77. * & allows the user to switch between them.
  78. *
  79. * @param int $visits The number of visits for this period & site. If <= 0, the
  80. * reports are not shown, since they will have no data.getReferrersReportsByDimensionView
  81. * @return string The report viewer HTML.
  82. */
  83. private function getReferrersReportsByDimensionView($visits)
  84. {
  85. $result = '';
  86. // only display the reports by dimension view if there are visits
  87. if ($visits > 0) {
  88. $referrersReportsByDimension = new View\ReportsByDimension('Referrers');
  89. $referrersReportsByDimension->addReport(
  90. 'Referrers_ViewAllReferrers', 'Referrers_WidgetGetAll', 'Referrers.getAll');
  91. $byTypeCategory = Piwik::translate('Referrers_ViewReferrersBy', Piwik::translate('Live_GoalType'));
  92. $referrersReportsByDimension->addReport(
  93. $byTypeCategory, 'Referrers_WidgetKeywords', 'Referrers.getKeywords');
  94. $referrersReportsByDimension->addReport($byTypeCategory, 'SitesManager_Sites', 'Referrers.getWebsites');
  95. $referrersReportsByDimension->addReport($byTypeCategory, 'Referrers_Campaigns', 'Referrers.getCampaigns');
  96. $bySourceCategory = Piwik::translate('Referrers_ViewReferrersBy', Piwik::translate('General_Source'));
  97. $referrersReportsByDimension->addReport($bySourceCategory, 'Referrers_Socials', 'Referrers.getSocials');
  98. $referrersReportsByDimension->addReport(
  99. $bySourceCategory, 'Referrers_SearchEngines', 'Referrers.getSearchEngines');
  100. $result = $referrersReportsByDimension->render();
  101. }
  102. return $result;
  103. }
  104. public function getSearchEnginesAndKeywords()
  105. {
  106. $view = new View('@Referrers/getSearchEnginesAndKeywords');
  107. $view->searchEngines = $this->getSearchEngines(true);
  108. $view->keywords = $this->getKeywords(true);
  109. return $view->render();
  110. }
  111. public function getReferrerType()
  112. {
  113. return $this->renderReport(__FUNCTION__);
  114. }
  115. /**
  116. * Returns or echo's a report that shows all search keyword, website and campaign
  117. * referrer information in one report.
  118. *
  119. * @return string The report HTML or nothing if $fetch is set to false.
  120. */
  121. public function getAll()
  122. {
  123. return $this->renderReport(__FUNCTION__);
  124. }
  125. public function getKeywords()
  126. {
  127. return $this->renderReport(__FUNCTION__);
  128. }
  129. public function getSearchEnginesFromKeywordId()
  130. {
  131. return $this->renderReport(__FUNCTION__);
  132. }
  133. public function getSearchEngines()
  134. {
  135. return $this->renderReport(__FUNCTION__);
  136. }
  137. public function getKeywordsFromSearchEngineId()
  138. {
  139. return $this->renderReport(__FUNCTION__);
  140. }
  141. public function indexWebsites()
  142. {
  143. $view = new View('@Referrers/indexWebsites');
  144. $view->websites = $this->getWebsites(true);
  145. $view->socials = $this->getSocials(true);
  146. return $view->render();
  147. }
  148. public function getWebsites()
  149. {
  150. return $this->renderReport(__FUNCTION__);
  151. }
  152. public function getSocials()
  153. {
  154. return $this->renderReport(__FUNCTION__);
  155. }
  156. public function getUrlsForSocial()
  157. {
  158. return $this->renderReport(__FUNCTION__);
  159. }
  160. public function indexCampaigns()
  161. {
  162. return View::singleReport(
  163. Piwik::translate('Referrers_Campaigns'),
  164. $this->getCampaigns(true));
  165. }
  166. public function getCampaigns()
  167. {
  168. return $this->renderReport(__FUNCTION__);
  169. }
  170. public function getKeywordsFromCampaignId()
  171. {
  172. return $this->renderReport(__FUNCTION__);
  173. }
  174. public function getUrlsFromWebsiteId()
  175. {
  176. return $this->renderReport(__FUNCTION__);
  177. }
  178. protected function getReferrersVisitorsByType($date = false)
  179. {
  180. if ($date === false) {
  181. $date = Common::getRequestVar('date', false);
  182. }
  183. // we disable the queued filters because here we want to get the visits coming from search engines
  184. // if the filters were applied we would have to look up for a label looking like "Search Engines"
  185. // which is not good when we have translations
  186. $dataTableReferrersType = Request::processRequest(
  187. "Referrers.getReferrerType", array('disable_queued_filters' => '1', 'date' => $date));
  188. $nameToColumnId = array(
  189. 'visitorsFromSearchEngines' => Common::REFERRER_TYPE_SEARCH_ENGINE,
  190. 'visitorsFromDirectEntry' => Common::REFERRER_TYPE_DIRECT_ENTRY,
  191. 'visitorsFromWebsites' => Common::REFERRER_TYPE_WEBSITE,
  192. 'visitorsFromCampaigns' => Common::REFERRER_TYPE_CAMPAIGN,
  193. );
  194. $return = array();
  195. foreach ($nameToColumnId as $nameVar => $columnId) {
  196. $value = 0;
  197. $row = $dataTableReferrersType->getRowFromLabel($columnId);
  198. if ($row !== false) {
  199. $value = $row->getColumn(Metrics::INDEX_NB_VISITS);
  200. }
  201. $return[$nameVar] = $value;
  202. }
  203. return $return;
  204. }
  205. protected $referrerTypeToLabel = array(
  206. Common::REFERRER_TYPE_DIRECT_ENTRY => 'Referrers_DirectEntry',
  207. Common::REFERRER_TYPE_SEARCH_ENGINE => 'Referrers_SearchEngines',
  208. Common::REFERRER_TYPE_WEBSITE => 'Referrers_Websites',
  209. Common::REFERRER_TYPE_CAMPAIGN => 'Referrers_Campaigns',
  210. );
  211. public function getEvolutionGraph($typeReferrer = false, array $columns = array(), array $defaultColumns = array())
  212. {
  213. $view = $this->getLastUnitGraph($this->pluginName, __FUNCTION__, 'Referrers.getReferrerType');
  214. $view->config->add_total_row = true;
  215. // configure displayed columns
  216. if (empty($columns)) {
  217. $columns = Common::getRequestVar('columns', false);
  218. if (false !== $columns) {
  219. $columns = Piwik::getArrayFromApiParameter($columns);
  220. }
  221. }
  222. if (false !== $columns) {
  223. $columns = !is_array($columns) ? array($columns) : $columns;
  224. }
  225. if (!empty($columns)) {
  226. $view->config->columns_to_display = $columns;
  227. } elseif (empty($view->config->columns_to_display) && !empty($defaultColumns)) {
  228. $view->config->columns_to_display = $defaultColumns;
  229. }
  230. // configure selectable columns
  231. if (Common::getRequestVar('period', false) == 'day') {
  232. $selectable = array('nb_visits', 'nb_uniq_visitors', 'nb_actions');
  233. } else {
  234. $selectable = array('nb_visits', 'nb_actions');
  235. }
  236. $view->config->selectable_columns = $selectable;
  237. // configure displayed rows
  238. $visibleRows = Common::getRequestVar('rows', false);
  239. if ($visibleRows !== false) {
  240. // this happens when the row picker has been used
  241. $visibleRows = Piwik::getArrayFromApiParameter($visibleRows);
  242. // typeReferrer is redundant if rows are defined, so make sure it's not used
  243. $view->config->custom_parameters['typeReferrer'] = false;
  244. } else {
  245. // use $typeReferrer as default
  246. if ($typeReferrer === false) {
  247. $typeReferrer = Common::getRequestVar('typeReferrer', false);
  248. }
  249. $label = self::getTranslatedReferrerTypeLabel($typeReferrer);
  250. $total = Piwik::translate('General_Total');
  251. if (!empty($view->config->rows_to_display)) {
  252. $visibleRows = $view->config->rows_to_display;
  253. } else {
  254. $visibleRows = array($label, $total);
  255. }
  256. $view->requestConfig->request_parameters_to_modify['rows'] = $label . ',' . $total;
  257. }
  258. $view->config->row_picker_match_rows_by = 'label';
  259. $view->config->rows_to_display = $visibleRows;
  260. $view->config->documentation = Piwik::translate('Referrers_EvolutionDocumentation') . '<br />'
  261. . Piwik::translate('General_BrokenDownReportDocumentation') . '<br />'
  262. . Piwik::translate('Referrers_EvolutionDocumentationMoreInfo', '&quot;'
  263. . Piwik::translate('Referrers_DetailsByReferrerType') . '&quot;');
  264. return $this->renderView($view);
  265. }
  266. public function getLastDistinctSearchEnginesGraph()
  267. {
  268. $view = $this->getLastUnitGraph($this->pluginName, __FUNCTION__, "Referrers.getNumberOfDistinctSearchEngines");
  269. $view->config->translations['Referrers_distinctSearchEngines'] = ucfirst(Piwik::translate('Referrers_DistinctSearchEngines'));
  270. $view->config->columns_to_display = array('Referrers_distinctSearchEngines');
  271. return $this->renderView($view);
  272. }
  273. public function getLastDistinctKeywordsGraph()
  274. {
  275. $view = $this->getLastUnitGraph($this->pluginName, __FUNCTION__, "Referrers.getNumberOfDistinctKeywords");
  276. $view->config->translations['Referrers_distinctKeywords'] = ucfirst(Piwik::translate('Referrers_DistinctKeywords'));
  277. $view->config->columns_to_display = array('Referrers_distinctKeywords');
  278. return $this->renderView($view);
  279. }
  280. public function getLastDistinctWebsitesGraph()
  281. {
  282. $view = $this->getLastUnitGraph($this->pluginName, __FUNCTION__, "Referrers.getNumberOfDistinctWebsites");
  283. $view->config->translations['Referrers_distinctWebsites'] = ucfirst(Piwik::translate('Referrers_DistinctWebsites'));
  284. $view->config->columns_to_display = array('Referrers_distinctWebsites');
  285. return $this->renderView($view);
  286. }
  287. public function getLastDistinctCampaignsGraph()
  288. {
  289. $view = $this->getLastUnitGraph($this->pluginName, __FUNCTION__, "Referrers.getNumberOfDistinctCampaigns");
  290. $view->config->translations['Referrers_distinctCampaigns'] = ucfirst(Piwik::translate('Referrers_DistinctCampaigns'));
  291. $view->config->columns_to_display = array('Referrers_distinctCampaigns');
  292. return $this->renderView($view);
  293. }
  294. function getKeywordsForPage()
  295. {
  296. Piwik::checkUserHasViewAccess($this->idSite);
  297. $requestUrl = '&date=previous1'
  298. . '&period=week'
  299. . '&idSite=' . $this->idSite;
  300. $topPageUrlRequest = $requestUrl
  301. . '&method=Actions.getPageUrls'
  302. . '&filter_limit=50'
  303. . '&format=original';
  304. $request = new Request($topPageUrlRequest);
  305. $request = $request->process();
  306. /** @var $request Map */
  307. $tables = $request->getDataTables();;
  308. $topPageUrl = false;
  309. $first = key($tables);
  310. if (!empty($first)) {
  311. $topPageUrls = $tables[$first];
  312. $topPageUrls = $topPageUrls->getRowsMetadata('url');
  313. $tmpTopPageUrls = array_values($topPageUrls);
  314. $topPageUrl = current($tmpTopPageUrls);
  315. }
  316. if (empty($topPageUrl)) {
  317. $topPageUrl = $this->site->getMainUrl();
  318. }
  319. $url = $topPageUrl;
  320. // HTML
  321. $api = SettingsPiwik::getPiwikUrl()
  322. . '?module=API&method=Referrers.getKeywordsForPageUrl'
  323. . '&format=php'
  324. . '&filter_limit=10'
  325. . '&token_auth=' . Piwik::getCurrentUserTokenAuth();
  326. $api .= $requestUrl;
  327. $code = '
  328. // This function will call the API to get best keyword for current URL.
  329. // Then it writes the list of best keywords in a HTML list
  330. function DisplayTopKeywords($url = "")
  331. {
  332. // Do not spend more than 1 second fetching the data
  333. @ini_set("default_socket_timeout", $timeout = 1);
  334. // Get the Keywords data
  335. $url = empty($url) ? "http://". $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"] : $url;
  336. $api = "' . $api . '&url=" . urlencode($url);
  337. $keywords = @unserialize(file_get_contents($api));
  338. if($keywords === false || isset($keywords["result"])) {
  339. // DEBUG ONLY: uncomment for troubleshooting an empty output (the URL output reveals the token_auth)
  340. // echo "Error while fetching the <a href=\'$api\'>Top Keywords from Piwik</a>";
  341. return;
  342. }
  343. // Display the list in HTML
  344. $url = htmlspecialchars($url, ENT_QUOTES);
  345. $output = "<h2>Top Keywords for <a href=\'$url\'>$url</a></h2><ul>";
  346. foreach($keywords as $keyword) {
  347. $output .= "<li>". $keyword . "</li>";
  348. }
  349. if(empty($keywords)) { $output .= "Nothing yet..."; }
  350. $output .= "</ul>";
  351. echo $output;
  352. }
  353. ';
  354. $jsonRequest = str_replace('format=php', 'format=json', $api);
  355. echo "<p>This widget is designed to work in your website directly.
  356. This widget makes it easy to use Piwik to <i>automatically display the list of Top Keywords</i>, for each of your website Page URLs.</p>
  357. <p>
  358. <b>Example API URL</b> - For example if you would like to get the top 10 keywords, used last week, to land on the page <a target='_blank' href='$topPageUrl'>$topPageUrl</a>,
  359. in format JSON: you would dynamically fetch the data using <a target='_blank' href='$jsonRequest&url=" . urlencode($topPageUrl) . "'>this API request URL</a>. Make sure you encode the 'url' parameter in the URL.</p>
  360. <p><b>PHP Function ready to use!</b> - If you use PHP on your website, we have prepared a small code snippet that you can copy paste in your Website PHP files. You can then simply call the function <code>DisplayTopKeywords();</code> anywhere in your template, at the bottom of the content or in your blog sidebar.
  361. If you run this code in your page $topPageUrl, it would output the following:";
  362. echo "<div style='width:400px;margin-left:20px;padding:10px;border:1px solid black;'>";
  363. function DisplayTopKeywords($url = "", $api)
  364. {
  365. // Do not spend more than 1 second fetching the data
  366. @ini_set("default_socket_timeout", $timeout = 1);
  367. // Get the Keywords data
  368. $url = empty($url) ? "http://" . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"] : $url;
  369. $api = $api . "&url=" . urlencode($url);
  370. $keywords = @unserialize(file_get_contents($api));
  371. if ($keywords === false || isset($keywords["result"])) {
  372. // DEBUG ONLY: uncomment for troubleshooting an empty output (the URL output reveals the token_auth)
  373. //echo "Error while fetching the <a href=\'".$api."\'>Top Keywords from Piwik</a>";
  374. return;
  375. }
  376. // Display the list in HTML
  377. $url = htmlspecialchars($url, ENT_QUOTES);
  378. $output = "<h2>Top Keywords for <a href=\'$url\'>$url</a></h2><ul>";
  379. foreach ($keywords as $keyword) {
  380. $output .= "<li>" . $keyword . "</li>";
  381. }
  382. if (empty($keywords)) {
  383. $output .= "Nothing yet...";
  384. }
  385. $output .= "</ul>";
  386. echo $output;
  387. }
  388. DisplayTopKeywords($topPageUrl, $api);
  389. echo "</div><br/>
  390. <p>Here is the PHP function that you can paste in your pages:</P>
  391. <textarea cols=60 rows=8>&lt;?php\n" . htmlspecialchars($code) . "\n DisplayTopKeywords();</textarea>
  392. ";
  393. echo "
  394. <p><strong>Notes</strong>: You can for example edit the code to to make the Top search keywords link to your Website search result pages.
  395. <br/>On medium to large traffic websites, we recommend to cache this data, as to minimize the performance impact of calling the Piwik API on each page view.
  396. </p>
  397. ";
  398. }
  399. /**
  400. * Returns the i18n-ized label for a referrer type.
  401. *
  402. * @param int $typeReferrer The referrer type. Referrer types are defined in Common class.
  403. * @return string The i18n-ized label.
  404. */
  405. public static function getTranslatedReferrerTypeLabel($typeReferrer)
  406. {
  407. $label = getReferrerTypeLabel($typeReferrer);
  408. return Piwik::translate($label);
  409. }
  410. /**
  411. * Returns the URL for the sparkline of visits with a specific referrer type.
  412. *
  413. * @param int $referrerType The referrer type. Referrer types are defined in Common class.
  414. * @return string The URL that can be used to get a sparkline image.
  415. */
  416. private function getReferrerUrlSparkline($referrerType)
  417. {
  418. $totalRow = Piwik::translate('General_Total');
  419. return $this->getUrlSparkline(
  420. 'getEvolutionGraph',
  421. array('columns' => array('nb_visits'),
  422. 'rows' => array(self::getTranslatedReferrerTypeLabel($referrerType), $totalRow),
  423. 'typeReferrer' => $referrerType)
  424. );
  425. }
  426. /**
  427. * Returns an array containing the number of distinct referrers for each
  428. * referrer type.
  429. *
  430. * @param bool|string $date The date to use when getting metrics. If false, the
  431. * date query param is used.
  432. * @return array The metrics.
  433. */
  434. private function getDistinctReferrersMetrics($date = false)
  435. {
  436. $propertyToAccessorMapping = array(
  437. 'numberDistinctSearchEngines' => 'getNumberOfDistinctSearchEngines',
  438. 'numberDistinctKeywords' => 'getNumberOfDistinctKeywords',
  439. 'numberDistinctWebsites' => 'getNumberOfDistinctWebsites',
  440. 'numberDistinctWebsitesUrls' => 'getNumberOfDistinctWebsitesUrls',
  441. 'numberDistinctCampaigns' => 'getNumberOfDistinctCampaigns',
  442. );
  443. $result = array();
  444. foreach ($propertyToAccessorMapping as $property => $method) {
  445. $result[$property] = $this->getNumericValue('Referrers.' . $method, $date);
  446. }
  447. return $result;
  448. }
  449. /**
  450. * Utility method that calculates evolution values for a set of current & past values
  451. * and sets properties on a View w/ HTML that displays the evolution percents.
  452. *
  453. * @param View $view The view to set properties on.
  454. * @param string $date The date of the current values.
  455. * @param array $currentValues Array mapping view property names w/ present values.
  456. * @param string $lastPeriodDate The date of the period in the past.
  457. * @param array $previousValues Array mapping view property names w/ past values. Keys
  458. * in this array should be the same as keys in $currentValues.
  459. */
  460. private function addEvolutionPropertiesToView($view, $date, $currentValues, $lastPeriodDate, $previousValues)
  461. {
  462. foreach ($previousValues as $name => $pastValue) {
  463. $currentValue = $currentValues[$name];
  464. $evolutionName = $name . 'Evolution';
  465. $view->$evolutionName = $this->getEvolutionHtml($date, $currentValue, $lastPeriodDate, $pastValue);
  466. }
  467. }
  468. }