* @package WP_Piwik */ class WP_Piwik { /** * * @var Runtime environment variables */ private static $revisionId = 2019110501, $version = '1.0.23', $blog_id, $pluginBasename = NULL, $logger, $settings, $request, $optionsPageId; /** * Constructor class to configure and register all WP-Piwik components */ public function __construct() { global $blog_id; self::$blog_id = (isset ( $blog_id ) ? $blog_id : 'n/a'); $this->openLogger (); $this->openSettings (); $this->setup (); $this->addFilters (); $this->addActions (); $this->addShortcodes (); } /** * Destructor class to finish logging */ public function __destruct() { $this->closeLogger (); } /** * Setup class to prepare settings and check for installation and update */ private function setup() { self::$pluginBasename = plugin_basename ( __FILE__ ); if (! $this->isInstalled ()) $this->installPlugin (); elseif ($this->isUpdated ()) $this->updatePlugin (); if ($this->isConfigSubmitted ()) $this->applySettings (); self::$settings->save (); } /** * Register WordPress actions */ private function addActions() { if ( is_admin () ) { add_action ( 'admin_menu', array ( $this, 'buildAdminMenu' ) ); add_action ( 'admin_post_save_wp-piwik_stats', array ( $this, 'onStatsPageSaveChanges' ) ); add_action ( 'load-post.php', array ( $this, 'addPostMetaboxes' ) ); add_action ( 'load-post-new.php', array ( $this, 'addPostMetaboxes' ) ); if ($this->isNetworkMode ()) { add_action ( 'network_admin_notices', array ( $this, 'showNotices' ) ); add_action ( 'network_admin_menu', array ( $this, 'buildNetworkAdminMenu' ) ); add_action ( 'update_site_option_blogname', array ( $this, 'onBlogNameChange' ) ); add_action ( 'update_site_option_siteurl', array ( $this, 'onSiteUrlChange' ) ); } else { add_action ( 'admin_notices', array ( $this, 'showNotices' ) ); add_action ( 'update_option_blogname', array ( $this, 'onBlogNameChange' ) ); add_action ( 'update_option_siteurl', array ( $this, 'onSiteUrlChange' ) ); } if ($this->isDashboardActive ()) add_action ( 'wp_dashboard_setup', array ( $this, 'extendWordPressDashboard' ) ); } if ($this->isToolbarActive ()) { add_action ( is_admin () ? 'admin_head' : 'wp_head', array ( $this, 'loadToolbarRequirements' ) ); add_action ( 'admin_bar_menu', array ( $this, 'extendWordPressToolbar' ), 1000 ); } if ($this->isTrackingActive ()) { if ( !is_admin () || $this->isAdminTrackingActive ()) { $prefix = is_admin ()?'admin':'wp'; add_action ( self::$settings->getGlobalOption ( 'track_codeposition' ) == 'footer' ? $prefix.'_footer' : $prefix.'_head', array ( $this, 'addJavascriptCode' ) ); if (self::$settings->getGlobalOption ( 'dnsprefetch' )) add_action ( $prefix.'_head', array ( $this, 'addDNSPrefetchTag' ) ); if ($this->isAddNoScriptCode ()) add_action ( $prefix.'_footer', array ( $this, 'addNoscriptCode' ) ); } if (self::$settings->getGlobalOption ( 'add_post_annotations' )) add_action ( 'transition_post_status', array ( $this, 'addPiwikAnnotation' ), 10, 3 ); } } /** * Register WordPress filters */ private function addFilters() { if (is_admin()) { add_filter ( 'plugin_row_meta', array ( $this, 'setPluginMeta' ), 10, 2 ); add_filter ( 'screen_layout_columns', array ( $this, 'onScreenLayoutColumns' ), 10, 2 ); } elseif ($this->isTrackingActive ()) { if ($this->isTrackFeed ()) { add_filter ( 'the_excerpt_rss', array ( $this, 'addFeedTracking' ) ); add_filter ( 'the_content', array ( $this, 'addFeedTracking' ) ); } if ($this->isAddFeedCampaign ()) { add_filter ( 'post_link', array ( $this, 'addFeedCampaign' ) ); } if ($this->isCrossDomainLinkingEnabled ()) { add_filter ( 'wp_redirect', array ( $this, 'forwardCrossDomainVisitorId' ) ); } } } /** * Register WordPress shortcodes */ private function addShortcodes() { if ($this->isAddShortcode ()) add_shortcode ( 'wp-piwik', array ( $this, 'shortcode' ) ); } /** * Install WP-Piwik for the first time */ private function installPlugin($isUpdate = false) { self::$logger->log ( 'Running WP-Piwik installation' ); if (! $isUpdate) $this->addNotice ( 'install', sprintf ( __ ( '%s %s installed.', 'wp-piwik' ), self::$settings->getGlobalOption ( 'plugin_display_name' ), self::$version ), __ ( 'Next you should connect to Piwik', 'wp-piwik' ) ); self::$settings->setGlobalOption ( 'revision', self::$revisionId ); self::$settings->setGlobalOption ( 'last_settings_update', time () ); } /** * Uninstall WP-Piwik */ public function uninstallPlugin() { self::$logger->log ( 'Running WP-Piwik uninstallation' ); if (! defined ( 'WP_UNINSTALL_PLUGIN' )) exit (); self::deleteWordPressOption ( 'wp-piwik-notices' ); self::$settings->resetSettings ( true ); } /** * Update WP-Piwik */ private function updatePlugin() { self::$logger->log ( 'Upgrade WP-Piwik to ' . self::$version ); $patches = glob ( dirname ( __FILE__ ) . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'update' . DIRECTORY_SEPARATOR . '*.php' ); $isPatched = false; if (is_array ( $patches )) { sort ( $patches ); foreach ( $patches as $patch ) { $patchVersion = ( int ) pathinfo ( $patch, PATHINFO_FILENAME ); if ($patchVersion && self::$settings->getGlobalOption ( 'revision' ) < $patchVersion) { self::includeFile ( 'update' . DIRECTORY_SEPARATOR . $patchVersion ); $isPatched = true; } } } if ((self::$settings->getGlobalOption('update_notice') == 'enabled') || ((self::$settings->getGlobalOption('update_notice') == 'script') && $isPatched)) $this->addNotice ( 'update', sprintf ( __ ( '%s updated to %s.', 'wp-piwik' ), self::$settings->getGlobalOption ( 'plugin_display_name' ), self::$version ), __ ( 'Please validate your configuration', 'wp-piwik' ) ); $this->installPlugin ( true ); } /** * Define a notice * * @param string $type * identifier * @param string $subject * notice headline * @param string $text * notice content * @param boolean $stay * set to true if the message should persist (default: false) */ private function addNotice($type, $subject, $text, $stay = false) { $notices = $this->getWordPressOption ( 'wp-piwik-notices', array () ); $notices [$type] = array ( 'subject' => $subject, 'text' => $text, 'stay' => $stay ); $this->updateWordPressOption ( 'wp-piwik-notices', $notices ); } /** * Show all notices defined previously * * @see addNotice() */ public function showNotices() { $link = sprintf ( '%s', __ ( 'Settings', 'wp-piwik' ) ); if ($notices = $this->getWordPressOption ( 'wp-piwik-notices' )) { foreach ( $notices as $type => $notice ) { printf ( '

%s %s: %s: %s

', $notice ['subject'], __ ( 'Important', 'wp-piwik' ), $notice ['text'], $link ); if (! $notice ['stay']) unset ( $notices [$type] ); } } $this->updateWordPressOption ( 'wp-piwik-notices', $notices ); } /** * Get the settings page URL * * @return string settings page URL */ private function getSettingsURL() { return (self::$settings->checkNetworkActivation () ? 'settings' : 'options-general') . '.php?page=' . self::$pluginBasename; } /** * Echo javascript tracking code */ public function addJavascriptCode() { if ($this->isHiddenUser ()) { self::$logger->log ( 'Do not add tracking code to site (user should not be tracked) Blog ID: ' . self::$blog_id . ' Site ID: ' . self::$settings->getOption ( 'site_id' ) ); return; } $trackingCode = new WP_Piwik\TrackingCode ( $this ); $trackingCode->is404 = (is_404 () && self::$settings->getGlobalOption ( 'track_404' )); $trackingCode->isUsertracking = self::$settings->getGlobalOption ( 'track_user_id' ) != 'disabled'; $trackingCode->isSearch = (is_search () && self::$settings->getGlobalOption ( 'track_search' )); self::$logger->log ( 'Add tracking code. Blog ID: ' . self::$blog_id . ' Site ID: ' . self::$settings->getOption ( 'site_id' ) ); if ($this->isNetworkMode () && self::$settings->getGlobalOption ( 'track_mode' ) == 'manually') { $siteId = $this->getPiwikSiteId (); if ($siteId != 'n/a') echo str_replace ( '{ID}', $siteId, $trackingCode->getTrackingCode () ); else echo ''; } else echo $trackingCode->getTrackingCode (); } /** * Echo DNS prefetch tag */ public function addDNSPrefetchTag() { echo ''; } /** * Get Piwik Domain */ public function getPiwikDomain() { switch (self::$settings->getGlobalOption ( 'piwik_mode' )) { case 'php' : return '//' . parse_url(self::$settings->getGlobalOption ( 'proxy_url' ), PHP_URL_HOST); case 'cloud' : return '//' . self::$settings->getGlobalOption ( 'piwik_user' ) . '.innocraft.cloud'; case 'cloud-matomo' : return '//' . self::$settings->getGlobalOption ( 'matomo_user' ) . '.matomo.cloud'; default : return '//' . parse_url(self::$settings->getGlobalOption ( 'piwik_url' ), PHP_URL_HOST); } } /** * Echo noscript tracking code */ public function addNoscriptCode() { if (self::$settings->getGlobalOption ( 'track_mode' ) == 'proxy') return; if ($this->isHiddenUser ()) { self::$logger->log ( 'Do not add noscript code to site (user should not be tracked) Blog ID: ' . self::$blog_id . ' Site ID: ' . self::$settings->getOption ( 'site_id' ) ); return; } self::$logger->log ( 'Add noscript code. Blog ID: ' . self::$blog_id . ' Site ID: ' . self::$settings->getOption ( 'site_id' ) ); echo self::$settings->getOption ( 'noscript_code' ) . "\n"; } /** * Register post view meta boxes */ public function addPostMetaboxes() { if (self::$settings->getGlobalOption ( 'add_customvars_box' )) { add_action ( 'add_meta_boxes', array ( new WP_Piwik\Template\MetaBoxCustomVars ( $this, self::$settings ), 'addMetabox' ) ); add_action ( 'save_post', array ( new WP_Piwik\Template\MetaBoxCustomVars ( $this, self::$settings ), 'saveCustomVars' ), 10, 2 ); } if (self::$settings->getGlobalOption ( 'perpost_stats' )) { add_action ( 'add_meta_boxes', array ( $this, 'onloadPostPage' ) ); } } /** * Register admin menu components */ public function buildAdminMenu() { if (self::isConfigured ()) { $cap = 'wp-piwik_read_stats'; if (self::$settings->checkNetworkActivation ()) { global $current_user; $userRoles = $current_user->roles; $allowed = self::$settings->getGlobalOption ( 'capability_read_stats' ); if (is_array($userRoles) && is_array($allowed)) foreach ($userRoles as $userRole) if (isset( $allowed[$userRole] ) && $allowed[$userRole]) { $cap = 'read'; break; } } $statsPage = new WP_Piwik\Admin\Statistics ( $this, self::$settings ); $this->statsPageId = add_dashboard_page ( __ ( 'Piwik Statistics', 'wp-piwik' ), self::$settings->getGlobalOption ( 'plugin_display_name' ), $cap, 'wp-piwik_stats', array ( $statsPage, 'show' ) ); $this->loadAdminStatsHeader ( $this->statsPageId, $statsPage ); } if (! self::$settings->checkNetworkActivation ()) { $optionsPage = new WP_Piwik\Admin\Settings ( $this, self::$settings ); self::$optionsPageId = add_options_page ( self::$settings->getGlobalOption ( 'plugin_display_name' ), self::$settings->getGlobalOption ( 'plugin_display_name' ), 'activate_plugins', __FILE__, array ( $optionsPage, 'show' ) ); $this->loadAdminSettingsHeader ( self::$optionsPageId, $optionsPage ); } } /** * Register network admin menu components */ public function buildNetworkAdminMenu() { if (self::isConfigured ()) { $statsPage = new WP_Piwik\Admin\Network ( $this, self::$settings ); $this->statsPageId = add_dashboard_page ( __ ( 'Piwik Statistics', 'wp-piwik' ), self::$settings->getGlobalOption ( 'plugin_display_name' ), 'manage_sites', 'wp-piwik_stats', array ( $statsPage, 'show' ) ); $this->loadAdminStatsHeader ( $this->statsPageId, $statsPage ); } $optionsPage = new WP_Piwik\Admin\Settings ( $this, self::$settings ); self::$optionsPageId = add_submenu_page ( 'settings.php', self::$settings->getGlobalOption ( 'plugin_display_name' ), self::$settings->getGlobalOption ( 'plugin_display_name' ), 'manage_sites', __FILE__, array ( $optionsPage, 'show' ) ); $this->loadAdminSettingsHeader ( self::$optionsPageId, $optionsPage ); } /** * Register admin header extensions for stats page * * @param $optionsPageId options * page id * @param $optionsPage options * page object */ public function loadAdminStatsHeader($statsPageId, $statsPage) { add_action ( 'admin_print_scripts-' . $statsPageId, array ( $statsPage, 'printAdminScripts' ) ); add_action ( 'admin_print_styles-' . $statsPageId, array ( $statsPage, 'printAdminStyles' ) ); add_action ( 'admin_head-' . $statsPageId, array ( $statsPage, 'extendAdminHeader' ) ); add_action ( 'load-' . $statsPageId, array ( $this, 'onloadStatsPage' ) ); } /** * Register admin header extensions for settings page * * @param $optionsPageId options * page id * @param $optionsPage options * page object */ public function loadAdminSettingsHeader($optionsPageId, $optionsPage) { add_action ( 'admin_head-' . $optionsPageId, array ( $optionsPage, 'extendAdminHeader' ) ); add_action ( 'admin_print_styles-' . $optionsPageId, array ( $optionsPage, 'printAdminStyles' ) ); } /** * Register WordPress dashboard widgets */ public function extendWordPressDashboard() { if (current_user_can ( 'wp-piwik_read_stats' )) { if (self::$settings->getGlobalOption ( 'dashboard_widget' ) != 'disabled') new WP_Piwik\Widget\Overview ( $this, self::$settings, 'dashboard', 'side', 'default', array ( 'date' => self::$settings->getGlobalOption ( 'dashboard_widget' ), 'period' => 'day' ) ); if (self::$settings->getGlobalOption ( 'dashboard_chart' )) new WP_Piwik\Widget\Chart ( $this, self::$settings ); if (self::$settings->getGlobalOption ( 'dashboard_ecommerce' )) new WP_Piwik\Widget\Ecommerce ( $this, self::$settings ); if (self::$settings->getGlobalOption ( 'dashboard_seo' )) new WP_Piwik\Widget\Seo ( $this, self::$settings ); } } /** * Register WordPress toolbar components */ public function extendWordPressToolbar($toolbar) { if (current_user_can ( 'wp-piwik_read_stats' ) && is_admin_bar_showing ()) { $id = WP_Piwik\Request::register ( 'VisitsSummary.getUniqueVisitors', array ( 'period' => 'day', 'date' => 'last30' ) ); $unique = $this->request ( $id ); $url = is_network_admin () ? $this->getSettingsURL () : false; $content = is_network_admin () ? __('Configure WP-Piwik', 'wp-piwik') : ''; // Leave if result array does contain a message instead of valid data if (isset($unique['result'])) $content .= ''; elseif (is_array ( $unique ) ) { $content = "Loading..."; $url = $this->getStatsURL (); } $toolbar->add_menu ( array ( 'id' => 'wp-piwik_stats', 'title' => $content, 'href' => $url ) ); } } /** * Add plugin meta data * * @param array $links * list of already defined plugin meta data * @param string $file * handled file * @return array complete list of plugin meta data */ public function setPluginMeta($links, $file) { if ($file == 'wp-piwik/wp-piwik.php' && (!$this->isNetworkMode () || is_network_admin()) ) return array_merge ( $links, array ( sprintf ( '%s', self::getSettingsURL (), __ ( 'Settings', 'wp-piwik' ) ) ) ); return $links; } /** * Prepare toolbar widget requirements */ public function loadToolbarRequirements() { if (is_admin_bar_showing ()) { wp_enqueue_script ( 'wp-piwik-sparkline', $this->getPluginURL () . 'js/sparkline/jquery.sparkline.min.js', array ( 'jquery' ), self::$version ); wp_enqueue_style ( 'wp-piwik', $this->getPluginURL () . 'css/wp-piwik-spark.css', array (), $this->getPluginVersion () ); } } /** * Add tracking pixels to feed content * * @param string $content * post content * @return string post content extended by tracking pixel */ public function addFeedTracking($content) { global $post; if (is_feed ()) { self::$logger->log ( 'Add tracking image to feed entry.' ); if (! self::$settings->getOption ( 'site_id' )) { $siteId = $this->requestPiwikSiteId (); if ($siteId != 'n/a') self::$settings->setOption ( 'site_id', $siteId ); else return false; } $title = the_title ( null, null, false ); $posturl = get_permalink ( $post->ID ); $urlref = get_bloginfo ( 'rss2_url' ); if (self::$settings->getGlobalOption ( 'track_mode' ) == 'proxy') $url = plugins_url ( 'wp-piwik' ) . '/proxy/piwik.php'; else { $url = self::$settings->getGlobalOption ( 'piwik_url' ); if (substr($url, -10, 10) == '/index.php') $url = str_replace('/index.php', '/piwik.php', $url); else $url .= 'piwik.php'; } $trackingImage = $url . '?idsite=' . self::$settings->getOption ( 'site_id' ) . '&rec=1&url=' . urlencode ( $posturl ) . '&action_name=' . urlencode ( $title ) . '&urlref=' . urlencode ( $urlref ); $content .= ''; } return $content; } /** * Add a campaign parameter to feed permalink * * @param string $permalink * permalink * @return string permalink extended by campaign parameter */ public function addFeedCampaign($permalink) { global $post; if (is_feed ()) { self::$logger->log ( 'Add campaign to feed permalink.' ); $sep = (strpos ( $permalink, '?' ) === false ? '?' : '&'); $permalink .= $sep . 'pk_campaign=' . urlencode ( self::$settings->getGlobalOption ( 'track_feed_campaign' ) ) . '&pk_kwd=' . urlencode ( $post->post_name ); } return $permalink; } /** * Forwards the cross domain parameter pk_vid if the URL parameter is set and a user is about to be redirected. * When another website links to WooCommerce with a pk_vid parameter, and WooCommerce redirects the user to another * URL, the pk_vid parameter would get lost and the visitorId would later not be applied by the tracking code * due to the lost pk_vid URL parameter. If the URL parameter is set, we make sure to forward this parameter. * * @param string $location * * @return string location extended by pk_vid URL parameter if the URL parameter is set */ public function forwardCrossDomainVisitorId($location) { if (!empty($_GET['pk_vid']) && preg_match('/^[a-zA-Z0-9]{24,48}$/', $_GET['pk_vid'])) { // currently, the pk_vid parameter is 32 characters long, but it may vary over time. $location = add_query_arg( 'pk_vid', $_GET['pk_vid'], $location ); } return $location; } /** * Apply settings update * * @return boolean settings update applied */ private function applySettings() { self::$settings->applyChanges ( $_POST ['wp-piwik'] ); if (self::$settings->getGlobalOption ( 'auto_site_config' ) && self::isConfigured ()) { if ($this->isPHPMode () && ! defined ( 'PIWIK_INCLUDE_PATH' )) self::definePiwikConstants (); $siteId = $this->getPiwikSiteId (); $trackingCode = $this->updateTrackingCode ( $siteId ); self::$settings->setOption ( 'site_id', $siteId ); } self::$settings->setGlobalOption ( 'revision', self::$revisionId ); self::$settings->setGlobalOption ( 'last_settings_update', time () ); return true; } /** * Check if WP-Piwik is configured * * @return boolean Is WP-Piwik configured? */ public static function isConfigured() { return (self::$settings->getGlobalOption ( 'piwik_token' ) && (self::$settings->getGlobalOption ( 'piwik_mode' ) != 'disabled') && (((self::$settings->getGlobalOption ( 'piwik_mode' ) == 'http') && (self::$settings->getGlobalOption ( 'piwik_url' ))) || ((self::$settings->getGlobalOption ( 'piwik_mode' ) == 'php') && (self::$settings->getGlobalOption ( 'piwik_path' ))) || ((self::$settings->getGlobalOption ( 'piwik_mode' ) == 'cloud') && (self::$settings->getGlobalOption ( 'piwik_user' ))) || ((self::$settings->getGlobalOption ( 'piwik_mode' ) == 'cloud-matomo') && (self::$settings->getGlobalOption ( 'matomo_user' ))))); } /** * Check if WP-Piwik was updated * * @return boolean Was WP-Piwik updated? */ private function isUpdated() { return self::$settings->getGlobalOption ( 'revision' ) && self::$settings->getGlobalOption ( 'revision' ) < self::$revisionId; } /** * Check if WP-Piwik is already installed * * @return boolean Is WP-Piwik installed? */ private function isInstalled() { $oldSettings = $this->getWordPressOption ( 'wp-piwik_global-settings', false ); if ($oldSettings && isset( $oldSettings['revision'] )) { self::log('Save old settings'); self::$settings->setGlobalOption ( 'revision', $oldSettings['revision'] ); } else self::log( 'Current revision '.self::$settings->getGlobalOption ( 'revision' ) ); return self::$settings->getGlobalOption ( 'revision' ) > 0; } /** * Check if new settings were submitted * * @return boolean Are new settings submitted? */ public static function isConfigSubmitted() { return isset ( $_POST ) && isset ( $_POST ['wp-piwik'] ) && self::isValidOptionsPost(); } /** * Check if PHP mode is chosen * * @return Is PHP mode chosen? */ public function isPHPMode() { return self::$settings->getGlobalOption ( 'piwik_mode' ) && self::$settings->getGlobalOption ( 'piwik_mode' ) == 'php'; } /** * Check if WordPress is running in network mode * * @return boolean Is WordPress running in network mode? */ public function isNetworkMode() { return self::$settings->checkNetworkActivation (); } /** * Check if a WP-Piwik dashboard widget is enabled * * @return boolean Is a dashboard widget enabled? */ private function isDashboardActive() { return self::$settings->getGlobalOption ( 'dashboard_widget' ) || self::$settings->getGlobalOption ( 'dashboard_chart' ) || self::$settings->getGlobalOption ( 'dashboard_seo' ); } /** * Check if a WP-Piwik toolbar widget is enabled * * @return boolean Is a toolbar widget enabled? */ private function isToolbarActive() { return self::$settings->getGlobalOption ( 'toolbar' ); } /** * Check if WP-Piwik tracking code insertion is enabled * * @return boolean Insert tracking code? */ private function isTrackingActive() { return self::$settings->getGlobalOption ( 'track_mode' ) != 'disabled'; } /** * Check if admin tracking is enabled * * @return boolean Is admin tracking enabled? */ private function isAdminTrackingActive() { return self::$settings->getGlobalOption ( 'track_admin' ) && is_admin (); } /** * Check if WP-Piwik noscript code insertion is enabled * * @return boolean Insert noscript code? */ private function isAddNoScriptCode() { return self::$settings->getGlobalOption ( 'track_noscript' ); } /** * Check if feed tracking is enabled * * @return boolean Is feed tracking enabled? */ private function isTrackFeed() { return self::$settings->getGlobalOption ( 'track_feed' ); } /** * Check if feed permalinks get a campaign parameter * * @return boolean Add campaign parameter to feed permalinks? */ private function isAddFeedCampaign() { return self::$settings->getGlobalOption ( 'track_feed_addcampaign' ); } /** * Check if feed permalinks get a campaign parameter * * @return boolean Add campaign parameter to feed permalinks? */ private function isCrossDomainLinkingEnabled() { return self::$settings->getGlobalOption ( 'track_crossdomain_linking' ); } /** * Check if WP-Piwik shortcodes are enabled * * @return boolean Are shortcodes enabled? */ private function isAddShortcode() { return self::$settings->getGlobalOption ( 'shortcodes' ); } /** * Define Piwik constants for PHP reporting API */ public static function definePiwikConstants() { if (! defined ( 'PIWIK_INCLUDE_PATH' )) { //@header('Content-type: text/html'); define ( 'PIWIK_INCLUDE_PATH', self::$settings->getGlobalOption ( 'piwik_path' ) ); define ( 'PIWIK_USER_PATH', self::$settings->getGlobalOption ( 'piwik_path' ) ); define ( 'PIWIK_ENABLE_DISPATCH', false ); define ( 'PIWIK_ENABLE_ERROR_HANDLER', false ); define ( 'PIWIK_ENABLE_SESSION_START', false ); } } /** * Start chosen logging method */ private function openLogger() { switch (WP_PIWIK_ACTIVATE_LOGGER) { case 1 : self::$logger = new WP_Piwik\Logger\Screen ( __CLASS__ ); break; case 2 : self::$logger = new WP_Piwik\Logger\File ( __CLASS__ ); break; default : self::$logger = new WP_Piwik\Logger\Dummy ( __CLASS__ ); } } /** * Log a message * * @param string $message * logger message */ public static function log($message) { self::$logger->log ( $message ); } /** * End logging */ private function closeLogger() { self::$logger = null; } /** * Load WP-Piwik settings */ private function openSettings() { self::$settings = new WP_Piwik\Settings ( $this, self::$logger ); if (! $this->isConfigSubmitted () && $this->isPHPMode () && ! defined ( 'PIWIK_INCLUDE_PATH' )) self::definePiwikConstants (); } /** * Include a WP-Piwik file */ private function includeFile($strFile) { self::$logger->log ( 'Include ' . $strFile . '.php' ); if (WP_PIWIK_PATH . $strFile . '.php') include (WP_PIWIK_PATH . $strFile . '.php'); } /** * Check if user should not be tracked * * @return boolean Do not track user? */ private function isHiddenUser() { if (is_multisite ()) foreach ( self::$settings->getGlobalOption ( 'capability_stealth' ) as $key => $val ) if ($val && current_user_can ( $key )) return true; return current_user_can ( 'wp-piwik_stealth' ); } /** * Check if tracking code is up to date * * @return boolean Is tracking code up to date? */ public function isCurrentTrackingCode() { return (self::$settings->getOption ( 'last_tracking_code_update' ) && self::$settings->getOption ( 'last_tracking_code_update' ) > self::$settings->getGlobalOption ( 'last_settings_update' )); } /** * DEPRECTAED Add javascript code to site header * * @deprecated * */ public function site_header() { self::$logger->log ( 'Using deprecated function site_header' ); $this->addJavascriptCode (); } /** * DEPRECTAED Add javascript code to site footer * * @deprecated * */ public function site_footer() { self::$logger->log ( 'Using deprecated function site_footer' ); $this->addNoscriptCode (); } /** * Identify new posts if an annotation is required * and create Piwik annotation * * @param string $newStatus * new post status * @param strint $oldStatus * new post status * @param object $post * current post object */ public function addPiwikAnnotation($newStatus, $oldStatus, $post) { $enabledPostTypes = self::$settings->getGlobalOption ( 'add_post_annotations' ); if (isset($enabledPostTypes[$post->post_type]) && $enabledPostTypes[$post->post_type] && $newStatus == 'publish' && $oldStatus != 'publish') { $note = 'Published: ' . $post->post_title . ' - URL: ' . get_permalink ( $post->ID ); $id = WP_Piwik\Request::register ( 'Annotations.add', array ( 'idSite' => $this->getPiwikSiteId (), 'date' => date ( 'Y-m-d' ), 'note' => $note ) ); $result = $this->request ( $id ); self::$logger->log ( 'Add post annotation. ' . $note . ' - ' . serialize ( $result ) ); } } /** * Get WP-Piwik's URL */ public function getPluginURL() { return trailingslashit ( plugins_url () . '/wp-piwik/' ); } /** * Get WP-Piwik's version */ public function getPluginVersion() { return self::$version; } /** * Enable three columns for WP-Piwik stats screen * * @param * array full list of column settings * @param * mixed current screen id * @return array updated list of column settings */ public function onScreenLayoutColumns($columns, $screen) { if (isset( $this->statsPageId ) && $screen == $this->statsPageId) $columns [$this->statsPageId] = 3; return $columns; } /** * Add tracking code to admin header */ function addAdminHeaderTracking() { $this->addJavascriptCode (); } /** * Get option value * * @param string $key * option key * @return mixed option value */ public function getOption($key) { return self::$settings->getOption ( $key ); } /** * Get global option value * * @param string $key * global option key * @return mixed global option value */ public function getGlobalOption($key) { return self::$settings->getGlobalOption ( $key ); } /** * Get stats page URL * * @return string stats page URL */ public function getStatsURL() { return admin_url () . '?page=wp-piwik_stats'; } /** * Execute WP-Piwik test script */ private function loadTestscript() { $this->includeFile ( 'debug' . DIRECTORY_SEPARATOR . 'testscript' ); } /** * Echo an error message * * @param string $message * message content */ private static function showErrorMessage($message) { echo '' . __ ( 'An error occured', 'wp-piwik' ) . ': ' . $message . ' [' . __ ( 'Support', 'wp-piwik' ) . ']'; } /** * Perform a Piwik request * * @param string $id * request ID * @return mixed request result */ public function request($id, $debug = false) { if ( self::$settings->getGlobalOption ( 'piwik_mode' ) == 'disabled' ) return 'n/a'; if (! isset ( self::$request ) || empty ( self::$request )) self::$request = (self::$settings->getGlobalOption ( 'piwik_mode' ) == 'http' || self::$settings->getGlobalOption ( 'piwik_mode' ) == 'cloud' || self::$settings->getGlobalOption ( 'piwik_mode' ) == 'cloud-matomo' ? new WP_Piwik\Request\Rest ( $this, self::$settings ) : new WP_Piwik\Request\Php ( $this, self::$settings )); if ($debug) return self::$request->getDebug ( $id ); return self::$request->perform ( $id ); } /** * Reset request object */ public function resetRequest() { if (is_object(self::$request)) self::$request->reset(); self::$request = NULL; } /** * Execute WP-Piwik shortcode * * @param array $attributes * attribute list */ public function shortcode($attributes) { shortcode_atts ( array ( 'title' => '', 'module' => 'overview', 'period' => 'day', 'date' => 'yesterday', 'limit' => 10, 'width' => '100%', 'height' => '200px', 'idsite' => '', 'language' => 'en', 'range' => false, 'key' => 'sum_daily_nb_uniq_visitors' ), $attributes ); $shortcodeObject = new \WP_Piwik\Shortcode ( $attributes, $this, self::$settings ); return $shortcodeObject->get(); } /** * Get Piwik site ID by blog ID * * @param int $blogId * which blog's Piwik site ID to get, default is the current blog * @return mixed Piwik site ID or n/a */ public function getPiwikSiteId($blogId = null) { if (! $blogId && $this->isNetworkMode ()) $blogId = get_current_blog_id (); $result = self::$settings->getOption ( 'site_id', $blogId ); self::$logger->log ( 'Database result: ' . $result ); return (! empty ( $result ) ? $result : $this->requestPiwikSiteId ( $blogId )); } /** * Get a detailed list of all Piwik sites * * @return array Piwik sites */ public function getPiwikSiteDetails() { $id = WP_Piwik\Request::register ( 'SitesManager.getSitesWithAtLeastViewAccess', array () ); $piwikSiteDetails = $this->request ( $id ); return $piwikSiteDetails; } /** * Estimate a Piwik site ID by blog ID * * @param int $blogId * which blog's Piwik site ID to estimate, default is the current blog * @return mixed Piwik site ID or n/a */ private function requestPiwikSiteId($blogId = null) { $isCurrent = ! self::$settings->checkNetworkActivation () || empty ( $blogId ); if (self::$settings->getGlobalOption ( 'auto_site_config' )) { $id = WP_Piwik\Request::register ( 'SitesManager.getSitesIdFromSiteUrl', array ( 'url' => $isCurrent ? get_bloginfo ( 'url' ) : get_blog_details ( $blogId )->siteurl ) ); $result = $this->request ( $id ); $this->log ( 'Tried to identify current site, result: ' . serialize ( $result ) ); if (is_array( $result ) && empty( $result )) $result = $this->addPiwikSite ( $blogId ); elseif ( $result != 'n/a' && isset($result [0]) ) $result = $result [0] ['idsite']; else $result = null; } else $result = null; self::$logger->log ( 'Get Piwik ID: WordPress site ' . ($isCurrent ? get_bloginfo ( 'url' ) : get_blog_details ( $blogId )->siteurl) . ' = Piwik ID ' . $result ); if ($result !== null) { self::$settings->setOption ( 'site_id', $result, $blogId ); if (self::$settings->getGlobalOption ( 'track_mode' ) != 'disabled' && self::$settings->getGlobalOption ( 'track_mode' ) != 'manually') { $code = $this->updateTrackingCode ( $result, $blogId ); } $this::$settings->save (); return $result; } return 'n/a'; } /** * Add a new Piwik * * @param int $blogId * which blog's Piwik site to create, default is the current blog * @return int Piwik site ID */ public function addPiwikSite($blogId = null) { $isCurrent = ! self::$settings->checkNetworkActivation () || empty ( $blogId ); // Do not add site if Piwik connection is unreliable if (! $this->request ( 'global.getPiwikVersion' )) return null; $id = WP_Piwik\Request::register ( 'SitesManager.addSite', array ( 'urls' => $isCurrent ? get_bloginfo ( 'url' ) : get_blog_details ( $blogId )->siteurl, 'siteName' => urlencode( $isCurrent ? get_bloginfo ( 'name' ) : get_blog_details ( $blogId )->blogname ) ) ); $result = (int) $this->request ( $id ); self::$logger->log ( 'Create Piwik ID: WordPress site ' . ($isCurrent ? get_bloginfo ( 'url' ) : get_blog_details ( $blogId )->siteurl) . ' = Piwik ID ' . $result ); if (empty ( $result )) return null; else { do_action('wp-piwik_site_created', $result); return $result; } } /** * Update a Piwik site's detail information * * @param int $siteId * which Piwik site to updated * @param int $blogId * which blog's Piwik site ID to get, default is the current blog */ private function updatePiwikSite($siteId, $blogId = null) { $isCurrent = ! self::$settings->checkNetworkActivation () || empty ( $blogId ); $id = WP_Piwik\Request::register ( 'SitesManager.updateSite', array ( 'idSite' => $siteId, 'urls' => $isCurrent ? get_bloginfo ( 'url' ) : get_blog_details ( $blogId )->siteurl, 'siteName' => $isCurrent ? get_bloginfo ( 'name' ) : get_blog_details ( $blogId )->blogname ) ); $this->request ( $id ); self::$logger->log ( 'Update Piwik site: WordPress site ' . ($isCurrent ? get_bloginfo ( 'url' ) : get_blog_details ( $blogId )->siteurl) ); } /** * Update a site's tracking code * * @param int $siteId * which Piwik site to updated * @param int $blogId * which blog's Piwik site ID to get, default is the current blog * @return string tracking code */ public function updateTrackingCode($siteId = false, $blogId = null) { if (!$siteId) $siteId = $this->getPiwikSiteId (); if (self::$settings->getGlobalOption ( 'track_mode' ) == 'disabled' || self::$settings->getGlobalOption ( 'track_mode' ) == 'manually') return false; $id = WP_Piwik\Request::register ( 'SitesManager.getJavascriptTag', array ( 'idSite' => $siteId, 'mergeSubdomains' => self::$settings->getGlobalOption ( 'track_across' ) ? 1 : 0, 'mergeAliasUrls' => self::$settings->getGlobalOption ( 'track_across_alias' ) ? 1 : 0, 'disableCookies' => self::$settings->getGlobalOption ( 'disable_cookies' ) ? 1 : 0, 'crossDomain' => self::$settings->getGlobalOption ( 'track_crossdomain_linking' ) ? 1 : 0, 'trackNoScript' => 1 ) ); $code = $this->request ( $id ); if (is_array($code) && isset($code['value'])) $code = $code['value']; $result = !is_array ( $code ) ? html_entity_decode ( $code ) : ''; self::$logger->log ( 'Delivered tracking code: ' . $result ); $result = WP_Piwik\TrackingCode::prepareTrackingCode ( $result, self::$settings, self::$logger, true ); if (isset ( $result ['script'] ) && ! empty ( $result ['script'] )) { self::$settings->setOption ( 'tracking_code', $result ['script'], $blogId ); self::$settings->setOption ( 'noscript_code', $result ['noscript'], $blogId ); self::$settings->setGlobalOption ( 'proxy_url', $result ['proxy'], $blogId ); } return $result; } /** * Update Piwik site if blog name changes * * @param string $oldValue * old blog name * @param string $newValue * new blog name */ public function onBlogNameChange($oldValue, $newValue = null) { $this->updatePiwikSite ( self::$settings->getOption ( 'site_id' ) ); } /** * Update Piwik site if blog URL changes * * @param string $oldValue * old blog URL * @param string $newValue * new blog URL */ public function onSiteUrlChange($oldValue, $newValue = null) { $this->updatePiwikSite ( self::$settings->getOption ( 'site_id' ) ); } /** * Register stats page meta boxes * * @param mixed $statsPageId * WordPress stats page ID */ public function onloadStatsPage($statsPageId) { if (self::$settings->getGlobalOption ( 'disable_timelimit' )) set_time_limit ( 0 ); wp_enqueue_script ( 'common' ); wp_enqueue_script ( 'wp-lists' ); wp_enqueue_script ( 'postbox' ); wp_enqueue_script ( 'wp-piwik', $this->getPluginURL () . 'js/wp-piwik.js', array (), self::$version, true ); wp_enqueue_script ( 'wp-piwik-jqplot', $this->getPluginURL () . 'js/jqplot/wp-piwik.jqplot.js', array ( 'jquery' ), self::$version ); new \WP_Piwik\Widget\Chart ( $this, self::$settings, $this->statsPageId ); new \WP_Piwik\Widget\Visitors ( $this, self::$settings, $this->statsPageId ); new \WP_Piwik\Widget\Overview ( $this, self::$settings, $this->statsPageId ); if (self::$settings->getGlobalOption ( 'stats_ecommerce' )) { new \WP_Piwik\Widget\Ecommerce ($this, self::$settings, $this->statsPageId); new \WP_Piwik\Widget\Items ($this, self::$settings, $this->statsPageId); new \WP_Piwik\Widget\ItemsCategory ($this, self::$settings, $this->statsPageId); } if (self::$settings->getGlobalOption ( 'stats_seo' )) new \WP_Piwik\Widget\Seo ( $this, self::$settings, $this->statsPageId ); new \WP_Piwik\Widget\Pages ( $this, self::$settings, $this->statsPageId ); new \WP_Piwik\Widget\Keywords ( $this, self::$settings, $this->statsPageId ); new \WP_Piwik\Widget\Referrers ( $this, self::$settings, $this->statsPageId ); new \WP_Piwik\Widget\Plugins ( $this, self::$settings, $this->statsPageId ); new \WP_Piwik\Widget\Search ( $this, self::$settings, $this->statsPageId ); new \WP_Piwik\Widget\Noresult ( $this, self::$settings, $this->statsPageId ); new \WP_Piwik\Widget\Browsers ( $this, self::$settings, $this->statsPageId ); new \WP_Piwik\Widget\BrowserDetails ( $this, self::$settings, $this->statsPageId ); new \WP_Piwik\Widget\Screens ( $this, self::$settings, $this->statsPageId ); new \WP_Piwik\Widget\Types ( $this, self::$settings, $this->statsPageId ); new \WP_Piwik\Widget\Models ( $this, self::$settings, $this->statsPageId ); new \WP_Piwik\Widget\Systems ( $this, self::$settings, $this->statsPageId ); new \WP_Piwik\Widget\SystemDetails ( $this, self::$settings, $this->statsPageId ); new \WP_Piwik\Widget\City ( $this, self::$settings, $this->statsPageId ); new \WP_Piwik\Widget\Country ( $this, self::$settings, $this->statsPageId ); } /** * Add per post statistics to a post's page * * @param mixed $postPageId * WordPress post page ID */ public function onloadPostPage($postPageId) { global $post; $postUrl = get_permalink ( $post->ID ); $this->log ( 'Load per post statistics: ' . $postUrl ); $locations = apply_filters( 'wp-piwik_meta_boxes_locations', array( 'post', 'page', 'custom_post_type' ) ); array ( new \WP_Piwik\Widget\Post ( $this, self::$settings, $locations, 'side', 'default', array ( 'url' => $postUrl ) ), 'show' ); } /** * Stats page changes by POST submit * * @see http://tinyurl.com/5r5vnzs */ function onStatsPageSaveChanges() { if (! current_user_can ( 'manage_options' )) wp_die ( __ ( 'Cheatin’ uh?' ) ); check_admin_referer ( 'wp-piwik_stats' ); wp_redirect ( $_POST ['_wp_http_referer'] ); } /** * Get option value, choose method depending on network mode * * @param string $option option key * @return string option value */ private function getWordPressOption($option, $default = null) { return ($this->isNetworkMode () ? get_site_option ( $option, $default ) : get_option ( $option, $default )); } /** * Delete option, choose method depending on network mode * * @param string $option option key */ private function deleteWordPressOption($option) { if ( $this->isNetworkMode () ) delete_site_option ( $option ); else delete_option ( $option ); } /** * Set option value, choose method depending on network mode * * @param string $option option key * @param mixed $value option value */ private function updateWordPressOption($option, $value) { if ( $this->isNetworkMode () ) update_site_option ( $option, $value ); else update_option ( $option, $value ); } /** * Check if WP-Piwik options page * * @return boolean True if current page is WP-Piwik's option page */ public static function isValidOptionsPost() { return is_admin() && check_admin_referer( 'wp-piwik_settings' ) && current_user_can( 'manage_options' ) ; } }