diff options
author | matt <matt@59fd770c-687e-43c8-a1e3-f5a4ff64c105> | 2008-12-26 16:50:57 +0300 |
---|---|---|
committer | matt <matt@59fd770c-687e-43c8-a1e3-f5a4ff64c105> | 2008-12-26 16:50:57 +0300 |
commit | 446fd843abd0640403c30a763493a8fb1d821160 (patch) | |
tree | 65ebec570ef05ae3f3d84e14a3e4cd7ab6b128ea | |
parent | 35d668736cc7596e9f48ac050ce685a45296cbb6 (diff) |
- cacheFile is now creating the directory if not already created
- adding log_conversion table, and goal table in 0.2.27
- adding case sensitive/case insensitive matching
- when goal plugin is disabled, conversions are not being recorded
- adding release notes in the Goal tab to let users know that this is alpha release
31 files changed, 392 insertions, 244 deletions
diff --git a/core/ArchiveProcessing/Day.php b/core/ArchiveProcessing/Day.php index 300234f3ce..9d0e3fd975 100644 --- a/core/ArchiveProcessing/Day.php +++ b/core/ArchiveProcessing/Day.php @@ -358,7 +358,6 @@ class Piwik_ArchiveProcessing_Day extends Piwik_ArchiveProcessing $oldRowToUpdate[Piwik_Archive::INDEX_NB_VISITS_CONVERTED] += $newRowToAdd['nb_visits_converted']; } - //TODO comment public function queryConversionsBySegment($segments = '') { if(!empty($segments)) diff --git a/core/CacheFile.php b/core/CacheFile.php index 156ef85703..a254788c52 100644 --- a/core/CacheFile.php +++ b/core/CacheFile.php @@ -58,12 +58,16 @@ class Piwik_CacheFile * @return bool True if the entry was succesfully stored */ function set($id, $content) - { + { + if( !is_dir($this->cachePath)) + { + Piwik_Common::mkdir($this->cachePath); + } if (!is_writable($this->cachePath)) { return false; } - $id = $this->cachePath . $id; + $id = $this->cachePath . $id . ".php"; $cache_literal = "<"."?php\n\n"; $cache_literal .= "$"."content = ".var_export($content, true).";\n\n"; diff --git a/core/Common.php b/core/Common.php index adfd7015b7..194e66a4c8 100644 --- a/core/Common.php +++ b/core/Common.php @@ -216,6 +216,40 @@ class Piwik_Common return $nameToValue; } + static public function mkdir( $path, $mode = 0755, $denyAccess = true ) + { + if(!is_dir($path)) + { + $directoryParent = Piwik_Common::realpath(dirname($path)); + if( is_writable($directoryParent) ) + { + mkdir($path, $mode, true); + } + } + + if($denyAccess) + { + self::createHtAccess($path); + } + } + + /** + * path without trailing slash + */ + static public function createHtAccess( $path ) + { + @file_put_contents($path . "/.htaccess", "Deny from all"); + } + + static public function realpath($path) + { + if (file_exists($path)) + { + return realpath($path); + } + return $path; + } + /** * Returns true if the string is a valid filename * File names that start with a-Z or 0-9 and contain a-Z, 0-9, underscore(_), dash(-), and dot(.) will be accepted. diff --git a/core/DataFiles/SearchEngines.php b/core/DataFiles/SearchEngines.php index af8891dca3..1076b56ff7 100644 --- a/core/DataFiles/SearchEngines.php +++ b/core/DataFiles/SearchEngines.php @@ -66,8 +66,9 @@ if(!isset($GLOBALS['Piwik_SearchEngines'] )) //Alice Adsl "rechercher.aliceadsl.fr" => array("Alice Adsl", "qs"), - "search.alice.it" => array("Alice (Virgilio)", "qt"), - + "search.alice.it" => array("Alice (powered by Virgilio)", "qt"), + "ricerca.alice.it" => array("Alice (powered by Virgilio)", "qs"), + //Allesklar "www.allesklar.de" => array("Allesklar", "words"), diff --git a/core/Log.php b/core/Log.php index 3291065e26..59f91c025b 100644 --- a/core/Log.php +++ b/core/Log.php @@ -52,7 +52,7 @@ abstract class Piwik_Log extends Zend_Log function addWriteToFile() { $writerFile = new Zend_Log_Writer_Stream($this->logToFileFilename); - Piwik::mkdir(Zend_Registry::get('config')->path->log); + Piwik_Common::mkdir(Zend_Registry::get('config')->path->log); $writerFile->setFormatter( $this->fileFormatter ); $this->addWriter($writerFile); } diff --git a/core/Piwik.php b/core/Piwik.php index 597d335257..aafe16655a 100644 --- a/core/Piwik.php +++ b/core/Piwik.php @@ -34,31 +34,6 @@ class Piwik ); /** - * path without trailing slash - */ - static public function createHtAccess( $path ) - { - @file_put_contents($path . "/.htaccess", "Deny from all"); - } - - static public function mkdir( $path, $mode = 0755, $denyAccess = true ) - { - if(!is_dir($path)) - { - $directoryParent = Piwik::realpath(dirname($path)); - if( is_writable($directoryParent) ) - { - mkdir($path, $mode, true); - } - } - - if($denyAccess) - { - Piwik::createHtAccess($path); - } - } - - /** * Checks that the directories Piwik needs write access are actually writable * Displays a nice error page if permissions are missing on some directories * @@ -72,7 +47,7 @@ class Piwik $directoryList = ''; foreach($resultCheck as $dir => $bool) { - $realpath = Piwik::realpath($dir); + $realpath = Piwik_Common::realpath($dir); if(!empty($realpath) && $bool === false) { $directoryList .= "<code>chmod 777 $realpath</code><br>"; @@ -117,10 +92,10 @@ class Piwik if(!file_exists($directoryToCheck)) { - Piwik::mkdir($directoryToCheck, 0755, false); + Piwik_Common::mkdir($directoryToCheck, 0755, false); } - $directory = Piwik::realpath($directoryToCheck); + $directory = Piwik_Common::realpath($directoryToCheck); $resultCheck[$directory] = false; if($directory !== false // realpath() returns FALSE on failure && is_writable($directoryToCheck)) @@ -131,15 +106,6 @@ class Piwik return $resultCheck; } - static public function realpath($path) - { - if (file_exists($path)) - { - return realpath($path); - } - return $path; - } - /** * Returns the Javascript code to be inserted on every page to track * @@ -547,6 +513,19 @@ class Piwik ) ", + 'goal' => " CREATE TABLE `{$prefixTables}goal` ( + `idsite` int(11) NOT NULL, + `idgoal` int(11) NOT NULL, + `name` varchar(50) NOT NULL, + `match_attribute` varchar(20) NOT NULL, + `pattern` varchar(255) NOT NULL, + `pattern_type` varchar(10) NOT NULL, + `case_sensitive` tinyint(4) NOT NULL, + `revenue` float NOT NULL, + `deleted` tinyint(4) NOT NULL default '0', + PRIMARY KEY (`idsite`,`idgoal`) + ) + ", 'logger_message' => "CREATE TABLE {$prefixTables}logger_message ( idlogger_message INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, @@ -644,6 +623,30 @@ class Piwik ) ", + 'log_conversion' => "CREATE TABLE `{$prefixTables}log_conversion` ( + `idvisit` int(10) unsigned NOT NULL, + `idsite` int(10) unsigned NOT NULL, + `visitor_idcookie` char(32) NOT NULL, + `server_time` datetime NOT NULL, + `visit_server_date` date NOT NULL, + `idaction` int(11) NOT NULL, + `idlink_va` int(11) NOT NULL, + `referer_idvisit` int(10) unsigned default NULL, + `referer_visit_server_date` date default NULL, + `referer_type` int(10) unsigned default NULL, + `referer_name` varchar(70) default NULL, + `referer_keyword` varchar(255) default NULL, + `visitor_returning` tinyint(1) NOT NULL, + `location_country` char(3) NOT NULL, + `location_continent` char(3) NOT NULL, + `url` text NOT NULL, + `idgoal` int(10) unsigned NOT NULL, + `revenue` float default NULL, + PRIMARY KEY (`idvisit`,`idgoal`), + KEY `index_idsite_date` (`idsite`,`visit_server_date`) + ) + ", + 'log_link_visit_action' => "CREATE TABLE {$prefixTables}log_link_visit_action ( idlink_va INTEGER(11) NOT NULL AUTO_INCREMENT, idvisit INTEGER(10) UNSIGNED NOT NULL, @@ -1151,8 +1154,8 @@ class Piwik static public function install() { - Piwik::mkdir(Zend_Registry::get('config')->smarty->compile_dir); - Piwik::mkdir(Zend_Registry::get('config')->smarty->cache_dir); + Piwik_Common::mkdir(Zend_Registry::get('config')->smarty->compile_dir); + Piwik_Common::mkdir(Zend_Registry::get('config')->smarty->cache_dir); } static public function uninstall() diff --git a/core/PluginsManager.php b/core/PluginsManager.php index 60c4f42f7a..a27bd2c937 100644 --- a/core/PluginsManager.php +++ b/core/PluginsManager.php @@ -401,9 +401,7 @@ class Piwik_PluginsManager } /** - * TODO horrible dirty hack because the Config class is not clean enough. Needs to rewrite the Config - * __set and __get in a cleaner way, also see the __destruct which writes the configuration file. - * + * TODO horrible dirty hack. Fix config class by merging both config files before reading. * @return array */ public function getInstalledPluginsName() diff --git a/core/Tracker/GoalManager.php b/core/Tracker/GoalManager.php index 85ef6ba808..d7f3b38726 100644 --- a/core/Tracker/GoalManager.php +++ b/core/Tracker/GoalManager.php @@ -25,8 +25,6 @@ class Piwik_Tracker_GoalManager $this->cookie = $cookie; } - //TODO goalid should be incrementing on a website basis - // load goal definitions from file static public function getGoalDefinitions( $idSite ) { $websiteAttributes = Piwik_Common::getCacheWebsiteAttributes( $idSite ); @@ -61,6 +59,10 @@ class Piwik_Tracker_GoalManager //TODO does this code work for manually triggered goals, with custom revenue? function detectGoals($idSite) { + if(!Piwik_PluginsManager::getInstance()->isPluginActivated('Goals')) + { + return false; + } $url = $this->action->getUrl(); $actionType = $this->action->getActionType(); $goals = $this->getGoalDefinitions($idSite); @@ -76,25 +78,44 @@ class Piwik_Tracker_GoalManager continue; } - //TODO: outlink trailing slash is automatically deleted, problem when trying to match? $pattern_type = $goal['pattern_type']; switch($pattern_type) { case 'regex': - $match = (preg_match('/' . $goal['pattern'] . '/', $url) == 1); + $pattern = '/' . $goal['pattern'] . '/'; + if(!$goal['case_sensitive']) + { + $pattern .= 'i'; + } + $match = (preg_match($pattern, $url) == 1); break; case 'contains': - $match = (strpos($url, $goal['pattern']) !== false); + if($goal['case_sensitive']) + { + $matched = strpos($url, $goal['pattern']); + } + else + { + $matched = stripos($url, $goal['pattern']); + } + $match = ($matched !== false); break; case 'exact': - $match = ($goal['pattern'] == $url); + if($goal['case_sensitive']) + { + $matched = strcmp($goal['pattern'], $url); + } + else + { + $matched = strcasecmp($goal['pattern'], $url); + } + $match = ($matched == 0); break; default: throw new Exception("Pattern type $pattern_type not valid."); break; } - if($match) { $this->matchedGoals[] = $goal; diff --git a/core/Updates/0.2.27.php b/core/Updates/0.2.27.php new file mode 100644 index 0000000000..4e04ee3eb0 --- /dev/null +++ b/core/Updates/0.2.27.php @@ -0,0 +1,18 @@ +<?php + +Piwik_Query( "ALTER TABLE `".Piwik::prefixTable('log_visit')."` + ADD `visit_goal_converted` VARCHAR( 1 ) NOT NULL AFTER `visit_total_time` ;"); +$tables = Piwik::getTablesCreateSql(); +Piwik_Query( $tables['log_conversion'] ); +Piwik_Query( $tables['goal'] ); + +$allTablesInstalled = Piwik::getTablesInstalled(); +foreach($allTablesInstalled as $tableName) +{ + if(preg_match('/archive_/', $tableName) == 1) + { + Piwik_Query('CREATE INDEX index_all + ON '. $tableName . ' (`idsite`,`date1`,`date2`,`name`,`ts_archived`)'); + + } +} diff --git a/core/Updates/0.2.28.php b/core/Updates/0.2.28.php deleted file mode 100644 index a64b2b2a72..0000000000 --- a/core/Updates/0.2.28.php +++ /dev/null @@ -1,9 +0,0 @@ -<?php - -Piwik_Query( "ALTER TABLE `".Piwik::prefixTable('log_visit')."` - ADD `visit_goal_converted` VARCHAR( 1 ) NOT NULL AFTER `visit_total_time` ;"); - -//TODO -// alter all archive_* -// KEY `index_all` (`idsite`,`date1`,`date2`,`name`,`ts_archived`) - diff --git a/core/Version.php b/core/Version.php index 89ad548c01..ce5455afda 100644 --- a/core/Version.php +++ b/core/Version.php @@ -1,5 +1,5 @@ <?php final class Piwik_Version { - const VERSION = '0.2.26'; + const VERSION = '0.2.27'; } diff --git a/core/ViewDataTable.php b/core/ViewDataTable.php index cc767a1337..e13f6b3d71 100644 --- a/core/ViewDataTable.php +++ b/core/ViewDataTable.php @@ -662,7 +662,10 @@ abstract class Piwik_ViewDataTable */ public function enableShowGoals() { - $this->viewProperties['show_goals'] = true; + if(Piwik_PluginsManager::getInstance()->isPluginActivated('Goals')) + { + $this->viewProperties['show_goals'] = true; + } } /** diff --git a/core/ViewDataTable/HtmlTable/AllColumns.php b/core/ViewDataTable/HtmlTable/AllColumns.php index bf84ff2ff0..2a83c9ae80 100644 --- a/core/ViewDataTable/HtmlTable/AllColumns.php +++ b/core/ViewDataTable/HtmlTable/AllColumns.php @@ -10,7 +10,6 @@ class Piwik_ViewDataTable_HtmlTable_AllColumns extends Piwik_ViewDataTable_HtmlT public function main() { - //TODO should be cached at least statically? $this->viewProperties['show_exclude_low_population'] = true; parent::main(); } diff --git a/core/ViewDataTable/HtmlTable/Goals.php b/core/ViewDataTable/HtmlTable/Goals.php index f1233fec6a..6711f7602c 100644 --- a/core/ViewDataTable/HtmlTable/Goals.php +++ b/core/ViewDataTable/HtmlTable/Goals.php @@ -47,6 +47,7 @@ class Piwik_ViewDataTable_HtmlTable_Goals extends Piwik_ViewDataTable_HtmlTable if($columnName == 'goal_%s_conversion_rate') { require_once "core/Tracker/GoalManager.php"; + require_once "plugins/Goals/API.php"; $goals = Piwik_Goals_API::getGoals( $this->getIdSite() ); foreach($goals as $goal) { @@ -1,45 +1,19 @@ Before Alpha ------------ -small -- no goals: no graph, form opened by default, easy to -- h3 should not be bold -- test [.*] pattern -- clarify that pattern need to be escaped -- display table by search engines, coutry, kwd, etc. -- update _visit schema + prepare update files >> -- test on piwik.org for one day, performance - -- test cacheFile code -- plugify all Goal related code - -Goal beta release Todo list ---------------------------- -- click on (more) leads to right sub report (start implementing #state) -- i18n -- documentation, screenshots, blog post - - -1h - new translations + updates 3h - small bugs report in robotrock, new search engines, etc. 1h - release -friday: -8h of work free to fix - -Following up show all columns new UI element -==== +To fix +====== +- <idsubdatatable>1</idsubdatatable> shouldnt be in api response - when used with visitsGenerator, in dowloads export XML, full_url and url is 0 -- add new column "overall visits with conversion" - post 29 There seems not to be a way to export the pages information widget. I wanted to download the entry pages to see where my visitors entered my site from, but there is no option to do so. - ADD forward of non true show_values to forward when specified from URL to ajax - disable show icon in some iframes and/or dashboard -- do proper CSS factoring - clarify 'false' '0' values etc. //convert all JS datatable footer parameter values to '1' or '0' -- documentation + Blog post -- exclude all population doesn't work for actions - cron should return errors when token doesn't have any website Bugs @@ -51,9 +25,12 @@ Bugs - In Referers->Evolution page, in addition, I think its melting titles because I read in spanish "Entrada directa nb_uniq_visitors" for the first graph, "Paginas web nb_uniq_visitors" for the second and so on. - +- exclude all population doesn't work for actions + Reports improvements ==================== +- add new column "overall visits with conversion" +- add visits with conversion sparkline in VisitsSummary overview - add link under widgets to report (optional display) - link under goal conversion to full goal reports (optional display) - think of ways to show entry / exit pages and bounce rate. @@ -87,10 +64,6 @@ high priority features - Loyalty (Most people visited: 1 times) and Recency (Most people last visited: X days ago) http://en.wikipedia.org/wiki/RFM -Small features -============== -- can we find a "binary operator string -> regex" conversion function? - User Interface improvements =========================== - add icon calendar http://developer.yahoo.com/ypatterns/pattern.php?pattern=calendar#Solution @@ -106,7 +79,7 @@ Code improvements ================= - plugins should listen to user delete/ site delete and delete their own user/site related data - why widgetize inherits Piwik_Widgetize_Controller -- PLUGINS HAVE THEIR OWN TESTS +- plugins could have their own tests, read automatically from the test suite Documentation ============= diff --git a/misc/testJavascriptTracker/index.php b/misc/testJavascriptTracker/index.php index 8361e50375..1de9ff8de3 100644 --- a/misc/testJavascriptTracker/index.php +++ b/misc/testJavascriptTracker/index.php @@ -52,4 +52,4 @@ piwik_log(piwik_action_name, piwik_idsite,piwik_url); </script><object> <noscript><p>Web analytics <img src="<?php echo $urlPiwik; ?>/piwik.php" style="border:0" alt="piwik"/></p> </noscript></object></a> -<!-- /Piwik -->
\ No newline at end of file +<!-- /Piwik --> diff --git a/plugins/Goals/API.php b/plugins/Goals/API.php index 7417bd1988..5b1b849f01 100644 --- a/plugins/Goals/API.php +++ b/plugins/Goals/API.php @@ -40,7 +40,7 @@ class Piwik_Goals_API return $cleanedGoals; } - public function addGoal( $idSite, $name, $matchAttribute, $pattern, $patternType, $revenue ) + public function addGoal( $idSite, $name, $matchAttribute, $pattern, $patternType, $caseSensitive, $revenue ) { Piwik::checkUserHasAdminAccess($idSite); // save in db @@ -52,8 +52,9 @@ class Piwik_Goals_API { $idGoal = 1; } - $name = urldecode($name); - $pattern = urldecode($pattern); + self::checkPatternIsValid($patternType, $pattern); + $name = self::checkName($name); + $pattern = self::checkPattern($pattern); $db->insert(Piwik::prefixTable('goal'), array( 'idsite' => $idSite, @@ -62,6 +63,7 @@ class Piwik_Goals_API 'match_attribute' => $matchAttribute, 'pattern' => $pattern, 'pattern_type' => $patternType, + 'case_sensitive' => $caseSensitive, 'revenue' => $revenue, 'deleted' => 0, )); @@ -69,23 +71,45 @@ class Piwik_Goals_API return $idGoal; } - public function updateGoal( $idSite, $idGoal, $name, $matchAttribute, $pattern, $patternType, $revenue ) + public function updateGoal( $idSite, $idGoal, $name, $matchAttribute, $pattern, $patternType, $caseSensitive, $revenue ) { Piwik::checkUserHasAdminAccess($idSite); - $name = urldecode($name); - $pattern = urldecode($pattern); + $name = self::checkName($name); + $pattern = self::checkPattern($pattern); + self::checkPatternIsValid($patternType, $pattern); Zend_Registry::get('db')->update( Piwik::prefixTable('goal'), array( 'name' => $name, 'match_attribute' => $matchAttribute, 'pattern' => $pattern, 'pattern_type' => $patternType, + 'case_sensitive' => $caseSensitive, 'revenue' => $revenue, ), "idsite = '$idSite' AND idgoal = '$idGoal'" ); Piwik_Common::regenerateCacheWebsiteAttributes($idSite); } + + private function checkPatternIsValid($patternType, $pattern) + { + if($patternType == 'exact' + && substr($pattern, 0, 4) != 'http') + { + throw new Exception("If you choose 'exact match', the matching string must be a + URL starting with http:// or https://. For example, 'http://www.yourwebsite.com/newsletter/subscribed.html'."); + } + } + + private function checkName($name) + { + return urldecode($name); + } + + private function checkPattern($pattern) + { + return urldecode($pattern); + } public function deleteGoal( $idSite, $idGoal ) { @@ -99,15 +123,15 @@ class Piwik_Goals_API Piwik_Common::regenerateCacheWebsiteAttributes($idSite); } - public function getConversionsReturningVisitors( $idSite, $period, $date, $idGoal = false ) - { - - } - - public function getConversionsNewVisitors( $idSite, $period, $date, $idGoal = false ) - { - - } +// public function getConversionsReturningVisitors( $idSite, $period, $date, $idGoal = false ) +// { +// +// } +// +// public function getConversionsNewVisitors( $idSite, $period, $date, $idGoal = false ) +// { +// +// } // TODO public function getConversionRateReturningVisitors( $idSite, $period, $date, $idGoal = false ) diff --git a/plugins/Goals/Controller.php b/plugins/Goals/Controller.php index 42fa706150..935d616258 100644 --- a/plugins/Goals/Controller.php +++ b/plugins/Goals/Controller.php @@ -121,6 +121,16 @@ class Piwik_Goals_Controller extends Piwik_Controller $view->userCanEditGoals = Piwik::isUserHasAdminAccess($idSite); echo $view->render(); } + + function addNewGoal() + { + $view = new Piwik_View('Goals/templates/add_new_goal.tpl'); + $idSite = Piwik_Common::getRequestVar('idSite'); + $view->userCanEditGoals = Piwik::isUserHasAdminAccess($idSite); + $view->currency = Piwik::getCurrency(); + $view->onlyShowAddNewGoal = true; + echo $view->render(); + } function getLastNbConversionsGraph( $fetch = false ) { diff --git a/plugins/Goals/Goals.php b/plugins/Goals/Goals.php index ae13724c44..550f0e7288 100644 --- a/plugins/Goals/Goals.php +++ b/plugins/Goals/Goals.php @@ -62,11 +62,18 @@ class Piwik_Goals extends Piwik_Plugin function addMenus() { - Piwik_AddMenu('Goals', 'Overview', array('module' => 'Goals')); $goals = Piwik_Tracker_GoalManager::getGoalDefinitions(Piwik_Common::getRequestVar('idSite')); - foreach($goals as $goal) + if(count($goals)==0) { - Piwik_AddMenu('Goals', str_replace('%', '%%', $goal['name']), array('module' => 'Goals', 'action' => 'goalReport', 'idGoal' => $goal['idgoal'])); + Piwik_AddMenu('Goals', 'Add a new Goal', array('module' => 'Goals', 'action' => 'addNewGoal')); + } + else + { + Piwik_AddMenu('Goals', 'Overview', array('module' => 'Goals')); + foreach($goals as $goal) + { + Piwik_AddMenu('Goals', str_replace('%', '%%', $goal['name']), array('module' => 'Goals', 'action' => 'goalReport', 'idGoal' => $goal['idgoal'])); + } } } diff --git a/plugins/Goals/templates/GoalForm.js b/plugins/Goals/templates/GoalForm.js index 27e250c5ca..4345bc8958 100644 --- a/plugins/Goals/templates/GoalForm.js +++ b/plugins/Goals/templates/GoalForm.js @@ -3,7 +3,7 @@ function showAddNewGoal() { $("#GoalForm").show(); $("#EditGoals").hide(); - lazyScrollTo("#bottom", 100); + $.scrollTo("#AddEditGoals", 400); return false; } @@ -11,12 +11,12 @@ function showEditGoals() { $("#EditGoals").show(); $("#GoalForm").hide(); - lazyScrollTo("#bottom", 100); + $.scrollTo("#AddEditGoals", 400); return false; } // init the goal form with existing goal value, if any -function initGoalForm(goalMethodAPI, submitText, goalName, matchAttribute, pattern, patternType, revenue, goalId) +function initGoalForm(goalMethodAPI, submitText, goalName, matchAttribute, pattern, patternType, caseSensitive, revenue, goalId) { $('#goal_name').val(goalName); $('input[@name=match_attribute][value='+matchAttribute+']').attr('checked', true); @@ -24,6 +24,7 @@ function initGoalForm(goalMethodAPI, submitText, goalName, matchAttribute, patte $('#examples_pattern').html(mappingMatchTypeExamples[matchAttribute]); $('option[value='+patternType+']').attr('selected', true); $('input[name=pattern]').val(pattern); + $('#case_sensitive').attr('checked', caseSensitive); $('input[name=revenue]').val(revenue); $('input[name=methodGoalAPI]').val(goalMethodAPI); $('#goal_submit').val(submitText); @@ -32,6 +33,11 @@ function initGoalForm(goalMethodAPI, submitText, goalName, matchAttribute, patte } } +function initAndShowAddGoalForm() +{ + initGoalForm('Goals.addGoal', 'Add Goal', '', 'url', '', 'contains', false, '0'); + return showAddNewGoal(); +} function bindGoalForm() { $('input[@name=match_attribute]').click( function() { @@ -46,8 +52,36 @@ function bindGoalForm() $.ajax( ajaxRequestAddGoal ); return false; }); + + $('a[name=linkAddNewGoal]').click( function(){ + initAndShowAddGoalForm(); + } ); } +function bindListGoalEdit() +{ + $('a[name=linkEditGoal]').click( function() { + var goalId = $(this).attr('id'); + var goal = piwik.goals[goalId]; + initGoalForm("Goals.updateGoal", "Update Goal", goal.name, goal.match_attribute, goal.pattern, goal.pattern_type, (goal.case_sensitive=='0' ? false : true), goal.revenue, goalId); + showAddNewGoal(); + return false; + }); + + $('a[name=linkDeleteGoal]').click( function() { + var goalId = $(this).attr('id'); + var goalName = 'test goal';//piwik.goals[goalId][name] + if(confirm(sprintf('Are you sure you want to delete the Goal %s?','"'+goalName+'"'))) + { + $.ajax( getAjaxDeleteGoal( goalId ) ); + return false; + } + }); + + $('a[name=linkEditGoals]').click( function(){ + return showEditGoals(); + } ); +} function getAjaxDeleteGoal(idGoal) { var ajaxRequest = getStandardAjaxConf(); @@ -76,6 +110,7 @@ function getAjaxAddGoal() parameters.matchAttribute = $('input[name=match_attribute][checked]').val(); parameters.patternType = $('[name=pattern_type]').val(); parameters.pattern = encodeURIComponent( $('input[name=pattern]').val() ); + parameters.caseSensitive = $('#case_sensitive').attr('checked') == true ? 1: 0; parameters.revenue = $('input[name=revenue]').val(); parameters.idGoal = $('input[name=goalIdUpdate]').val(); diff --git a/plugins/Goals/templates/add_edit_goal.tpl b/plugins/Goals/templates/add_edit_goal.tpl index 1f0220bcf6..2ca55ca102 100644 --- a/plugins/Goals/templates/add_edit_goal.tpl +++ b/plugins/Goals/templates/add_edit_goal.tpl @@ -1,103 +1,29 @@ <div id="AddEditGoals"> +{if isset($onlyShowAddNewGoal)} + <h2>Add a new Goal</h2> +{else} + <h2><a onclick='' name="linkAddNewGoal">+ Add a new Goal</a> + or <a onclick='' name="linkEditGoals">Edit</a> existing Goals</h2> +{/if} - <h2><a href='#' name="linkAddNewGoal">+ Add a new Goal</a> - or <a href='#' name="linkEditGoals">Edit</a> existing Goals</h2> - - <script> - piwik.goals = {$goalsJSON}; - </script> - <div> <div id="ajaxError" style="display:none"></div> <div id="ajaxLoading" style="display:none"><div id="loadingPiwik"><img src="themes/default/images/loading-blue.gif" alt="" /> {'General_LoadingData'|translate}</div></div> </div> - <span id='EditGoals' style="display:none;"> - <table class="tableForm"> - <thead style="font-weight:bold"> - <td>Id</td> - <td>Goal Name</td> - <td>Goal is Triggered when</td> - <td>Revenue</td> - <td>Edit</td> - <td>Delete</td> - </thead> - {foreach from=$goals item=goal} - <tr> - <td>{$goal.idgoal}</td> - <td>{$goal.name}</td> - <td>{$goal.match_attribute} <br>Pattern {$goal.pattern_type}: {$goal.pattern}</b></td> - <td>{if $goal.revenue==0}-{else}{$currency}{$goal.revenue}{/if}</td> - <td><a href='#' name="linkEditGoal" id="{$goal.idgoal}"><img src='plugins/UsersManager/images/edit.png' border=0> Edit</a></td> - <td><a href='#' name="linkDeleteGoal" id="{$goal.idgoal}"><img src='plugins/UsersManager/images/remove.png' border=0> Delete</a></td> - </tr> - {/foreach} - </table> - </span> - - <span id='GoalForm' style="display:none;"> - <form> - <table class="tableForm"> - <tr> - <td>Goal Name </td> - <td><input type="text" name="name" value="" id="goal_name" /></td> - </tr> - <tr> - <td>Goal is triggered when visitors:</td> - <td> - <input type="radio" onclick="" checked="true" id="match_attribute_url" value="url" name="match_attribute"/> - <label for="match_attribute_url">Visit a given URL (page or group of pages)</label> - <br> - <input type="radio" onclick="" id="match_attribute_file" value="file" name="match_attribute"/> - <label for="match_attribute_file">Download a file</label> - <br> - <input type="radio" onclick="" id="match_attribute_external_website" value="external_website" name="match_attribute"/> - <label for="match_attribute_external_website">Click on a Link to an external website </label> - </td> - </tr> - <tr> - <td>where the <span id="match_attribute_name"></span></td> - <td> - <select name="pattern_type"> - <option value="contains">contains</option> - <option value="exact">is exactly</option> - <option value="regex">matches the expression</option> - </select> - - <input type="text" name="pattern" value=""/> - <br> - <div id="examples_pattern"></div> - </td> - </tr> - <tr> - <td>(optional) Goal default value is </td> - <td>{$currency} <input type="text" name="revenue" size="1" value="0"/></td> - </tr> - <tr> - <td colspan="2" style="border:0"> - <div class="submit"> - <input type="hidden" name="methodGoalAPI" value=""> - <input type="hidden" name="goalIdUpdate" value=""> - <input type="submit" value="Add Goal" name="submit" id="goal_submit" class="submit" /> - </div> - </td> - </tr> - </table> - </form> - </span> +{if !isset($onlyShowAddNewGoal)} + {include file="Goals/templates/list_goal_edit.tpl"} +{/if} + {include file="Goals/templates/form_add_goal.tpl"} <a id='bottom'></a> </div> {literal} -<style> -#examples_pattern { - color:#9B9B9B; -} -</style> <script type="text/javascript" src="plugins/Goals/templates/GoalForm.js"></script> <script language="javascript"> + var mappingMatchTypeName = { "url": "URL", "file": "filename", @@ -109,34 +35,15 @@ var mappingMatchTypeExamples = { "external_website": "eg. contains 'amazon.com'<br>eg. is exactly 'http://mypartner.com/landing.html'<br>eg. matches the expression 'http://www.amazon.com\\\/[.*]\\\/yourAffiliateId'" }; -$('a[name=linkEditGoal]').click( function() { - var goalId = $(this).attr('id'); - var goal = piwik.goals[goalId]; - initGoalForm("Goals.updateGoal", "Update Goal", goal.name, goal.match_attribute, goal.pattern, goal.pattern_type, goal.revenue, goalId); - showAddNewGoal(); - return false; -}); - -$('a[name=linkDeleteGoal]').click( function() { - var goalId = $(this).attr('id'); - var goalName = 'test goal';//piwik.goals[goalId][name] - if(confirm(sprintf('Are you sure you want to delete the Goal %s?','"'+goalName+'"'))) - { - $.ajax( getAjaxDeleteGoal( goalId ) ); - return false; - } -}); - bindGoalForm(); -$('a[name=linkAddNewGoal]').click( function(){ - initGoalForm('Goals.addGoal', 'Add Goal', '', 'url', '', 'contains', '0'); - return showAddNewGoal(); -} ); -$('a[name=linkEditGoals]').click( function(){ - return showEditGoals(); -} ); +{/literal} -</script> +{if !isset($onlyShowAddNewGoal)} +piwik.goals = {$goalsJSON}; +bindListGoalEdit(); +{else} +initAndShowAddGoalForm(); +{/if} -{/literal} +</script> diff --git a/plugins/Goals/templates/add_new_goal.tpl b/plugins/Goals/templates/add_new_goal.tpl new file mode 100644 index 0000000000..05a7f66e8d --- /dev/null +++ b/plugins/Goals/templates/add_new_goal.tpl @@ -0,0 +1,8 @@ + +{if $userCanEditGoals} + {include file=Goals/templates/add_edit_goal.tpl} +{else} +Only an Administrator or the Super User can add Goals for a given website. +Please ask your Piwik administrator to set up a Goal for your website. +<br>Tracking Goals are a great tool to help you maximize your website performance! +{/if} diff --git a/plugins/Goals/templates/form_add_goal.tpl b/plugins/Goals/templates/form_add_goal.tpl new file mode 100644 index 0000000000..95c4f6d3d9 --- /dev/null +++ b/plugins/Goals/templates/form_add_goal.tpl @@ -0,0 +1,67 @@ +{literal} +<style> +.goalInlineHelp{ +color:#9B9B9B; +} +</style> +{/literal} +<span id='GoalForm' style="display:none;"> +<form> + <table class="tableForm"> + <tr> + <td>Goal Name </td> + <td><input type="text" name="name" value="" id="goal_name" /></td> + </tr> + <tr> + <td>Goal is triggered when visitors:</td> + <td> + <input type="radio" id="match_attribute_url" value="url" name="match_attribute"/> + <label for="match_attribute_url">Visit a given URL (page or group of pages)</label> + <br> + <input type="radio" id="match_attribute_file" value="file" name="match_attribute"/> + <label for="match_attribute_file">Download a file</label> + <br> + <input type="radio" id="match_attribute_external_website" value="external_website" name="match_attribute"/> + <label for="match_attribute_external_website">Click on a Link to an external website </label> + </td> + </tr> + <tr> + <td>where the <span id="match_attribute_name"></span></td> + <td> + <select name="pattern_type"> + <option value="contains">contains</option> + <option value="exact">is exactly</option> + <option value="regex">matches the expression</option> + </select> + + <input type="text" name="pattern" value=""/> + <br> + <div id="examples_pattern" class="goalInlineHelp"></div> + <br> + <span style="float:right"> + (optional) <input type="checkbox" id="case_sensitive"/> + <label for="case_sensitive">Case sensitive match</label> + </span> + </td> + </tr> + <tr> + <td>(optional) Goal default value is </td> + <td>{$currency} <input type="text" name="revenue" size="1" value="0"/> + <div class="goalInlineHelp"> + For example, a Contact Form submitted by a visitor <br> + may be worth $10 on average. Piwik will help you understand <br> + how well your visitors segments are performing.</div> + </td> + </tr> + <tr> + <td colspan="2" style="border:0"> + <div class="submit"> + <input type="hidden" name="methodGoalAPI" value=""> + <input type="hidden" name="goalIdUpdate" value=""> + <input type="submit" value="Add Goal" name="submit" id="goal_submit" class="submit" /> + </div> + </td> + </tr> + </table> +</form> +</span>
\ No newline at end of file diff --git a/plugins/Goals/templates/list_goal_edit.tpl b/plugins/Goals/templates/list_goal_edit.tpl new file mode 100644 index 0000000000..081497cade --- /dev/null +++ b/plugins/Goals/templates/list_goal_edit.tpl @@ -0,0 +1,22 @@ +<span id='EditGoals' style="display:none;"> + <table class="tableForm"> + <thead style="font-weight:bold"> + <td>Id</td> + <td>Goal Name</td> + <td>Goal is Triggered when</td> + <td>Revenue</td> + <td>Edit</td> + <td>Delete</td> + </thead> + {foreach from=$goals item=goal} + <tr> + <td>{$goal.idgoal}</td> + <td>{$goal.name}</td> + <td>{$goal.match_attribute} <br>Pattern {$goal.pattern_type}: {$goal.pattern}</b></td> + <td>{if $goal.revenue==0}-{else}{$currency}{$goal.revenue}{/if}</td> + <td><a href='#' name="linkEditGoal" id="{$goal.idgoal}"><img src='plugins/UsersManager/images/edit.png' border=0> Edit</a></td> + <td><a href='#' name="linkDeleteGoal" id="{$goal.idgoal}"><img src='plugins/UsersManager/images/remove.png' border=0> Delete</a></td> + </tr> + {/foreach} + </table> +</span>
\ No newline at end of file diff --git a/plugins/Goals/templates/overview.tpl b/plugins/Goals/templates/overview.tpl index a17611066d..04bf1af90d 100644 --- a/plugins/Goals/templates/overview.tpl +++ b/plugins/Goals/templates/overview.tpl @@ -1,12 +1,10 @@ {include file="Goals/templates/title_and_evolution_graph.tpl"} - - {foreach from=$goalMetrics item=goal} {assign var=nb_conversions value=$goal.nb_conversions} {assign var=conversion_rate value=$goal.conversion_rate} -<h3 style="text-decoration:underline;padding-top:20px">{$goal.name} (goal)</h3> +<h2 style="padding-top: 30px;">{$goal.name} (goal)</h3> <table width=700px> <tr><td> <p>{sparkline src=$goal.urlSparklineConversions}<span> @@ -22,5 +20,8 @@ {/foreach} {if $userCanEditGoals} + <hr style="margin:30px 0px"> {include file=Goals/templates/add_edit_goal.tpl} {/if} + +{include file="Goals/templates/release_notes.tpl}
\ No newline at end of file diff --git a/plugins/Goals/templates/release_notes.tpl b/plugins/Goals/templates/release_notes.tpl new file mode 100644 index 0000000000..dce9ec63b2 --- /dev/null +++ b/plugins/Goals/templates/release_notes.tpl @@ -0,0 +1,20 @@ +<hr> +<b>About the Goal Tracking Plugin</b><br> +<pre> +The Goal Tracking Plugin is in alpha release. There is more coming soon! +- The Goal Report page will display conversion table by search engines, country, keyword, campaign, etc. +- The Goal Overview page will link to a Goal Report page with a "(more)" link that will ajax reload the page +- Goals could be triggered using javascript event, with custom revenue +- internationalization of all strings +- provide documentation, screenshots, blog post + add screenshot and inline help in "Add a New Goal" +- provide widgets for the dashboard, general goal overview, and one widget for each goal. With: graph evolution, sparklines. Widget with top segments for each goal. + +Known bugs +- The Goal total nb conversions should be sum of all goal conversions (wrong number when deleting a Goal) +- After adding goal, the window should refresh to the goal report page, and not to the dashboard +- Outlink trailing slash is automatically deleted from the URL, there would be a problem when trying to exact match a URL with trailing slash +- All graph labelling are not correct (always printing nb_uniq_visitors even when showing conversion or conversion_rate) see <a href='http://dev.piwik.org/trac/ticket/322'>#322</a> + +Give us Feedback! +If you find any other bug, or if you have suggestions, please send us a message using the "Give us feedback" link at the top of the Piwik pages. +</pre>
\ No newline at end of file diff --git a/plugins/Goals/templates/single_goal.tpl b/plugins/Goals/templates/single_goal.tpl index bb04e6f01b..b605c17490 100644 --- a/plugins/Goals/templates/single_goal.tpl +++ b/plugins/Goals/templates/single_goal.tpl @@ -4,8 +4,8 @@ <h2>Conversions Overview</h2> <ul class="ulGoalTopElements"> <li>Your best converting countries are: {include file='Goals/templates/list_top_segment.tpl' topSegment=$topSegments.country}</li> - <li>Your top converting keywords are: {include file='Goals/templates/list_top_segment.tpl' topSegment=$topSegments.keyword}</li> - <li>Your best converting websites referers are: {include file='Goals/templates/list_top_segment.tpl' topSegment=$topSegments.website}</li> + {if count($topSegments.keyword)>0}<li>Your top converting keywords are: {include file='Goals/templates/list_top_segment.tpl' topSegment=$topSegments.keyword}</li>{/if} + {if count($topSegments.website)>0}<li>Your best converting websites referers are: {include file='Goals/templates/list_top_segment.tpl' topSegment=$topSegments.website}</li>{/if} <li>Returning visitors conversion rate is <b>{$conversion_rate_returning}%</b>, New Visitors conversion rate is <b>{$conversion_rate_new}%</b></li> </ul> {/if} diff --git a/plugins/Goals/templates/title_and_evolution_graph.tpl b/plugins/Goals/templates/title_and_evolution_graph.tpl index f5359132d9..0b1b8d2c7b 100644 --- a/plugins/Goals/templates/title_and_evolution_graph.tpl +++ b/plugins/Goals/templates/title_and_evolution_graph.tpl @@ -18,4 +18,3 @@ </td></tr> </table> -<div style="clear:both">
\ No newline at end of file diff --git a/plugins/VisitsSummary/Controller.php b/plugins/VisitsSummary/Controller.php index 953c90a7d9..4b2cc72e56 100644 --- a/plugins/VisitsSummary/Controller.php +++ b/plugins/VisitsSummary/Controller.php @@ -29,7 +29,6 @@ class Piwik_VisitsSummary_Controller extends Piwik_Controller $view->sumVisitLength = $dataTableVisit->getColumn('sum_visit_length'); $view->bounceCount = $dataTableVisit->getColumn('bounce_count'); $view->maxActions = $dataTableVisit->getColumn('max_actions'); - //TODO visits with conversion } function getSparklines() diff --git a/tests/core/ReleaseCheckList.test.php b/tests/core/ReleaseCheckList.test.php index c308da3975..329a329376 100644 --- a/tests/core/ReleaseCheckList.test.php +++ b/tests/core/ReleaseCheckList.test.php @@ -47,7 +47,9 @@ class Test_Piwik_ReleaseCheckList extends UnitTestCase public function test_checkThatGivenPluginsAreDisabledByDefault() { $pluginsShouldBeDisabled = array( - 'DBStats' + 'DBStats', + 'Goals', + 'Live', ); foreach($pluginsShouldBeDisabled as $pluginName) { diff --git a/themes/default/common.css b/themes/default/common.css index bbc6505903..d2123e4753 100644 --- a/themes/default/common.css +++ b/themes/default/common.css @@ -45,6 +45,8 @@ body { } a { color: #0F1B2E; + text-decoration:underline; + cursor:pointer; } #loadingPiwik { |