commit 25f3879ece32a254296ed2ce9c21b05356ed66ea Author: Jaroslaw Rozanski Date: Mon Dec 27 01:15:36 2021 +0100 Wide Angle Analytics WordPress plugin 1.0.0 submitted for review diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..98a812e --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/data +/wordpress +**/*.log \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..2c19943 --- /dev/null +++ b/README.md @@ -0,0 +1,25 @@ +# WordPress Plugin for Wide Angle Analytics + +Easily add [Wide Angle Analytics](https://wideangle.co) tracker script to your WordPress site. You can quickly configure your web analytics tracker script. + +![waa_for_wp-01](https://user-images.githubusercontent.com/4896588/147422633-05962399-d832-478a-a83a-c69daa791879.png) + + +* Requires at least: 5.2 +* Tested up to: 5.8.2 +* Requires PHP: 7.4 + + +**Wide Angle Analytics** 📈 is a privacy-friendly, GDPR-compliant web analytics service. You can deploy it cookieless or with cookies enabled. + +We promote remote configuration, meaning you configure the tracker behaviour directly from our service interface. However, to give you full control, some settings must be applied before initial communication with our service takes place. + +We provide you with the ability to configure the tracker script with few settings, making sure that you are tracking your traffic effectively. At the same time, we give you tools to prevent leaking any or unintended Personal Data. + +Our plugin offers you as easy to use configuration wizard. The plugin will automatically inject the necessary HTML to both Header and Footer to make the script record website visits. + +![screenshot-1](https://user-images.githubusercontent.com/4896588/147422408-06696860-dae3-49f2-827d-bbd4af2bca04.jpg) + +## License + +Licensed under [GPLv2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html). diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 120000 index 0000000..84d6fb4 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1 @@ +docker/docker-compose.yaml \ No newline at end of file diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml new file mode 100644 index 0000000..78e3121 --- /dev/null +++ b/docker/docker-compose.yaml @@ -0,0 +1,29 @@ +version: '3.3' +services: + db: + container_name: 'local-wordpress-db' + image: 'mysql:5.7' + volumes: + - './data/mysql:/var/lib/mysql' + ports: + - 18766:3306 + environment: + MYSQL_ROOT_PASSWORD: somewordpress + MYSQL_DATABASE: wordpress_db + MYSQL_USER: wordpress_user + MYSQL_PASSWORD: wordpress_password + wordpress: + container_name: 'local-wordpress' + depends_on: + - db + image: 'wordpress:latest' + ports: + - '8080:80' + environment: + WORDPRESS_DB_HOST: 'db:3306' + WORDPRESS_DB_USER: wordpress_user + WORDPRESS_DB_PASSWORD: wordpress_password + WORDPRESS_DB_NAME: wordpress_db + volumes: + - "./wordpress:/var/www/html" + - "./plugins:/var/www/html/wp-content/plugins" \ No newline at end of file diff --git a/plugins/wide-angle-analytics/assets/banner-1544x500.png b/plugins/wide-angle-analytics/assets/banner-1544x500.png new file mode 100755 index 0000000..48722f1 Binary files /dev/null and b/plugins/wide-angle-analytics/assets/banner-1544x500.png differ diff --git a/plugins/wide-angle-analytics/assets/banner-772x250.png b/plugins/wide-angle-analytics/assets/banner-772x250.png new file mode 100755 index 0000000..01fcafd Binary files /dev/null and b/plugins/wide-angle-analytics/assets/banner-772x250.png differ diff --git a/plugins/wide-angle-analytics/assets/icon-128x128.png b/plugins/wide-angle-analytics/assets/icon-128x128.png new file mode 100755 index 0000000..326dd28 Binary files /dev/null and b/plugins/wide-angle-analytics/assets/icon-128x128.png differ diff --git a/plugins/wide-angle-analytics/assets/icon-256x256.png b/plugins/wide-angle-analytics/assets/icon-256x256.png new file mode 100755 index 0000000..8b4b2b4 Binary files /dev/null and b/plugins/wide-angle-analytics/assets/icon-256x256.png differ diff --git a/plugins/wide-angle-analytics/assets/icon.svg b/plugins/wide-angle-analytics/assets/icon.svg new file mode 100755 index 0000000..c006a99 --- /dev/null +++ b/plugins/wide-angle-analytics/assets/icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/plugins/wide-angle-analytics/assets/screenshot-1.jpg b/plugins/wide-angle-analytics/assets/screenshot-1.jpg new file mode 100644 index 0000000..4a52165 Binary files /dev/null and b/plugins/wide-angle-analytics/assets/screenshot-1.jpg differ diff --git a/plugins/wide-angle-analytics/readme.txt b/plugins/wide-angle-analytics/readme.txt new file mode 100644 index 0000000..3d9c494 --- /dev/null +++ b/plugins/wide-angle-analytics/readme.txt @@ -0,0 +1,30 @@ +=== Wide Angle Analytics === +Contributors: jrozanski,inputobjects +Tags: web analytics, tracking, web traffic, analytics +Requires at least: 5.2 +Tested up to: 5.8.2 +Requires PHP: 7.4 +Stable tag: trunk +License: GPLv2 + +Easily add Wide Angle Analytics tracker script to your WordPress site. You can quickly configure your web analytics tracker script. + +== Description == +Wide Angle Analytics is a privacy-friendly, GDPR-compliant web analytics service. You can deploy it cookieless or with cookies enabled. + +We promote remote configuration, meaning you configure the tracker behaviour directly from our service interface. However, to give you full control, some settings must be applied before initial communication with our service takes place. + +We provide you with the ability to configure the tracker script with few settings, making sure that you are tracking your traffic effectively. At the same time, we give you tools to prevent leaking any or unintended Personal Data. + +Our plugin offers you as easy to use configuration wizard. The plugin will automatically inject the necessary HTML to both Header and Footer to make the script record website visits. + +== Screenshots == +1. Configuration Wizard in Settings + +== Frequently Asked Questions == += Do I need Wide Angle Analytics account? = + +Yes. To start using tracking code, you will need a valid Site ID. The Site ID is available in Wide Angle Analytics Site Settings panel. + += Where can I find detailed documentation about Wide Angle Analytics? = +You will find most of your answers in the Knowledge Base. Should you require further assistance, please get in touch with our team. \ No newline at end of file diff --git a/plugins/wide-angle-analytics/types/WideAngleConfig.php b/plugins/wide-angle-analytics/types/WideAngleConfig.php new file mode 100644 index 0000000..09d3106 --- /dev/null +++ b/plugins/wide-angle-analytics/types/WideAngleConfig.php @@ -0,0 +1,80 @@ +siteId = $siteId; + $this->trackerDomain = $trackerDomain; + $this->ignoreHash = $ignoreHash; + $this->exclusionString = $exclusionString; + $this->includeParamsString = $includeParamsString; + $this->helpers = new WideAngleHelpers(); + } + + function generateHeaderScript() { + $script = << +EOD; + return $script; + } + + function generateFooterScript() { + $pathExlusionsAttribute = $this->generateExclusionsAttribute(); + $includeParamsAttribute = $this->generateIncludeParamsAttribute(); + + $script = << +EOD; + return preg_replace("/(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+/", "\n", $script); + } + + private function generateIncludeParamsAttribute() { + $params = $this->helpers->parseIncludeParamsSetting($this->includeParamsString); + if(sizeof($params) > 0) { + return "data-waa-inc-params=\"" . implode(",", $params) . "\""; + } + return ""; + } + + private function generateExclusionsAttribute() { + $pathExlusionsAttribute = ""; + $exclusions = $this->helpers->parseExclusionSetting($this->exclusionString); + if(sizeof($exclusions) > 0) { + $pathExlusionsAttribute = $this->generateExclusionsAttributeValue($exclusions); + } + + $pathExlusionsAttributeWithKey = ""; + if(trim($pathExlusionsAttribute) != "") { + $pathExlusionsAttributeWithKey = "data-waa-exc-paths=\"" . $pathExlusionsAttribute ."\""; + } + return $pathExlusionsAttributeWithKey; + } + + private function generateExclusionsAttributeValue($exclusions) { + $accumulator = array(); + foreach($exclusions as $exclusion) { + switch($exclusion->get_type()) { + case "start": + array_push($accumulator, "^" . preg_quote($exclusion->get_value()) . ".*"); + break; + case "end": + array_push($accumulator, ".*" . preg_quote($exclusion->get_value()) . "$"); + break; + case "regex": + array_push($accumulator, $exclusion->get_value()); + break; + } + } + return implode(",", $accumulator); + } +} +?> \ No newline at end of file diff --git a/plugins/wide-angle-analytics/types/WideAngleExclusion.php b/plugins/wide-angle-analytics/types/WideAngleExclusion.php new file mode 100644 index 0000000..f7399a3 --- /dev/null +++ b/plugins/wide-angle-analytics/types/WideAngleExclusion.php @@ -0,0 +1,21 @@ +type = $type; + $this->value = $value; + } + + public function get_type() { + return $this->type; + } + + public function get_value() { + return $this->value; + } +} + +?> \ No newline at end of file diff --git a/plugins/wide-angle-analytics/types/WideAngleHelpers.php b/plugins/wide-angle-analytics/types/WideAngleHelpers.php new file mode 100644 index 0000000..606d6f2 --- /dev/null +++ b/plugins/wide-angle-analytics/types/WideAngleHelpers.php @@ -0,0 +1,78 @@ +plugin->folder . '/types/WideAngleExclusion.php' ); + +class WideAngleHelpers { + + + + function normalizeBoolean($value) { + $trimmed = trim($value); + switch($trimmed) { + case "": + case "false": + case "off": + return "false"; + case "on": + case "true": + return "true"; + } + } + + function normalizeTrackerDomain($domain) { + return "https://" . parse_url($domain, PHP_URL_HOST); + } + + function parseIncludeParamsSetting($params) { + if(trim($params) !== "") { + return preg_split("/\|\:/", $params); + } else { + return array(); + } + } + + function parseRequestIncludeParams($request) { + $pattern = "/^waa_inc_params_(\d{1,2})$/"; + $params = array(); + foreach($request as $key => $value) { + if(preg_match($pattern, $key)) { + array_push($params, trim($value)); + } + } + return $params; + } + + function parseExclusionSetting($path) { + $flatExclusions = $path; + $exclusions = preg_split("/\|\:/", $flatExclusions); + $exclusionPattern = '/^\[([A-Za-z0-9]{1,10})\](.*)$/'; + $matches = array(); + $parsedExclusions = array(); + + + foreach($exclusions as $exclusion) { + if(preg_match($exclusionPattern, $exclusion, $matches) > 0) { + array_push($parsedExclusions, new WideAngleExclusion($matches[1], $matches[2])); + } + } + return $parsedExclusions; + } + + function parseRequestExclusionPaths($request) { + $pattern = "/^waa_exc_path_(\d{1,2})_type$/"; + $exclusions = array(); + foreach($request as $key => $exclusionType) { + $idx = array(); + if(preg_match($pattern, $key, $idx)) { + $valueKey = "waa_exc_path_".$idx[1]."_value"; + $exclusionValue = trim($request[$valueKey]); + if($exclusionValue != null && $exclusionValue != "") { + $typedExclusion = "[" . $exclusionType . "]" .$exclusionValue; + array_push($exclusions, $typedExclusion); + } + } + } + return $exclusions; + } +} + +?> \ No newline at end of file diff --git a/plugins/wide-angle-analytics/views/admin_settings.php b/plugins/wide-angle-analytics/views/admin_settings.php new file mode 100644 index 0000000..b064019 --- /dev/null +++ b/plugins/wide-angle-analytics/views/admin_settings.php @@ -0,0 +1,241 @@ +settings[self::WAA_CONF_SITE_ID]; +$trackerDomain = $this->settings[self::WAA_CONF_TRACKER_DOMAIN]; +$ignoreHash = filter_var($this->settings[self::WAA_CONF_IGNORE_HASH], FILTER_VALIDATE_BOOLEAN); +$parsedExclusions = $this->plugin->helpers->parseExclusionSetting($this->settings[self::WAA_CONF_EXC_PATHS]); +$parsedIncludeParams = $this->plugin->helpers->parseIncludeParamsSetting($this->settings[self::WAA_CONF_INC_PARAMS]); +?> +
+

+ plugin->displayName; ?> » +

+ +
+

Configure your Wide Angle Analytics tracker script

+
+ Need help? +

Our documentation has dedicated section about: +

+

+
+
+ + message ) ) { + ?> +

message; ?>

+ errorMessage ) ) { + ?> +

errorMessage; ?>

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + plugin->name, $this->plugin->name . '_nonce' ); ?> +

Press save to generate and preview new script. +

+
+
+

Script generated from saved settings

+ +
+<head>
+<!-- .. -->
+settings[self::WAA_CONF_GENERATED_HEADER_SCRIPT]; ?>
+
+</head>
+<!-- .. -->
+settings[self::WAA_CONF_GENERATED_FOOTER_SCRIPT]; ?>
+
+
+
+
+
+ \ No newline at end of file diff --git a/plugins/wide-angle-analytics/wide-angle-analytics.php b/plugins/wide-angle-analytics/wide-angle-analytics.php new file mode 100644 index 0000000..63f1fdc --- /dev/null +++ b/plugins/wide-angle-analytics/wide-angle-analytics.php @@ -0,0 +1,189 @@ + +plugin = new stdClass; + $this->plugin->name = 'wide-angle-analytics'; + $this->plugin->displayName = 'Wide Angle Analytics'; + $this->plugin->folder = plugin_dir_path( __FILE__ ); + include_once( $this->plugin->folder . '/types/WideAngleHelpers.php' ); + + $this->plugin->helpers = new WideAngleHelpers(); + $this->plugin->exclusionTypes = array( + "start" => "Starts with", + "end" => "Ends with", + "regex" => "RegEx", + ); + + add_action( 'admin_init', array( &$this, 'registerPluginSettings' ) ); + add_action( 'admin_menu', array( &$this, 'registerAdminMenu' )); + add_action('wp_head', array( &$this, 'renderHeaderScript')); + add_action('wp_footer', array( &$this, 'renderFooterScript')); + } + + /** + * When script is configured and saved, function will render prefetch script directive. + * Inteded to be used with 'wp_head' hook. + */ + function renderHeaderScript() { + $this->renderSetting(self::WAA_CONF_GENERATED_HEADER_SCRIPT); + } + + /** + * When script is configured and saved, function will render Wide Angle Analytics script. + * Inteded to be used with 'wp_footer' hook. + */ + function renderFooterScript() { + $this->renderSetting(self::WAA_CONF_GENERATED_FOOTER_SCRIPT); + } + + /** + * When called, renders content of named setting. + * Rendering is omitted if current view is: Admin, Feed, Robots or Trackback. + */ + function renderSetting($setting) { + if ( + is_admin() || + is_feed() || + is_robots() || + is_trackback()) { + return; + } + + $script = get_option($setting); + if(trim($script) === "") { + return; + } + echo wp_unslash($script); + } + + /** + * Adds Wide Angle Analytics configuration menu to Admin "Settings" menu. + */ + function registerAdminMenu() { + add_submenu_page( + 'options-general.php', + $this->plugin->displayName, + $this->plugin->displayName, + 'manage_options', + $this->plugin->name, + array( &$this, 'adminPanelHandler' ) + ); + } + + /** + * Handle configuration submission. + * + * When successful, the generated script will rendered and storedin plugin keyed setting. + * This setting will be subsequently used when time comes to render it. The intermediate settings + * are parsed and processed only during configuration change. + * + */ + function adminPanelHandler() { + if ( ! current_user_can( 'manage_options' ) ) { + wp_die( __( 'Insufficient permissions. You are not allows to modify setting.', $this->plugin->displayName ) ); + } + if ( isset( $_REQUEST['submit'] ) ) { + if ( ! isset( $_REQUEST[ $this->plugin->name . '_nonce' ] ) ) { + $this->errorMessage = __( 'Nonce field is missing. Settings NOT saved.',$this->plugin->name ); + } elseif ( ! wp_verify_nonce( $_REQUEST[ $this->plugin->name . '_nonce' ], $this->plugin->name ) ) { + $this->errorMessage = __( 'Invalid nonce specified. Settings NOT saved.', $this->plugin->name ); + } else { + $waaSiteId = $_REQUEST['waa_site_id']; + $waaTrackerDomain = $this->plugin->helpers->normalizeTrackerDomain(trim($_REQUEST['waa_tracker_domain'])); + $waaIgnoreHash = $this->plugin->helpers->normalizeBoolean($_REQUEST['waa_ignore_hash']); + $waaExclusionPaths = implode(self::WAA_SEPARTOR, $this->plugin->helpers->parseRequestExclusionPaths($_REQUEST)); + $waaIncParams = implode(self::WAA_SEPARTOR, $this->plugin->helpers->parseRequestIncludeParams($_REQUEST)); + + include_once( $this->plugin->folder . '/types/WideAngleConfig.php' ); + $config = new WideAngleConfig($waaSiteId, $waaTrackerDomain, $waaIgnoreHash, $waaExclusionPaths, $waaIncParams); + + update_option(self::WAA_CONF_GENERATED_FOOTER_SCRIPT, $config->generateFooterScript()); + update_option(self::WAA_CONF_GENERATED_HEADER_SCRIPT, $config->generateHeaderScript()); + update_option(self::WAA_CONF_SITE_ID, $waaSiteId ); + update_option(self::WAA_CONF_TRACKER_DOMAIN, $waaTrackerDomain); + update_option(self::WAA_CONF_IGNORE_HASH, $waaIgnoreHash ); + update_option(self::WAA_CONF_EXC_PATHS, $waaExclusionPaths ); + update_option(self::WAA_CONF_INC_PARAMS, $waaIncParams); + } + } + $this->settings = array( + self::WAA_CONF_SITE_ID => esc_html(get_option( self::WAA_CONF_SITE_ID)), + self::WAA_CONF_EXC_PATHS => esc_html(get_option( self::WAA_CONF_EXC_PATHS)), + self::WAA_CONF_INC_PARAMS => esc_html(get_option( self::WAA_CONF_INC_PARAMS)), + self::WAA_CONF_TRACKER_DOMAIN => esc_html(get_option( self::WAA_CONF_TRACKER_DOMAIN)), + self::WAA_CONF_IGNORE_HASH => esc_html(get_option( self::WAA_CONF_IGNORE_HASH)), + self::WAA_CONF_GENERATED_HEADER_SCRIPT => esc_html(get_option( self::WAA_CONF_GENERATED_HEADER_SCRIPT )), + self::WAA_CONF_GENERATED_FOOTER_SCRIPT => esc_html(get_option( self::WAA_CONF_GENERATED_FOOTER_SCRIPT )), + ); + include_once( $this->plugin->folder . '/views/admin_settings.php' ); + } + + /** + * Creates settings for Wide Angle Analytics plugin. + * + * Following settings are registered: + * - waa_site_id + * - waa_tracker_domain + * - waa_exc_path + * - waa_inc_params + * - waa_ignore_hash + * - waa_header_script + * - waa_footer_script + */ + function registerPluginSettings() { + register_setting( $this->plugin->name, self::WAA_CONF_SITE_ID, array( + 'sanitize_callback' => 'trim', + ) ); + register_setting( $this->plugin->name, self::WAA_CONF_EXC_PATHS, array( + 'sanitize_callback' => 'trim', + ) ); + register_setting( $this->plugin->name, self::WAA_CONF_INC_PARAMS, array( + 'sanitize_callback' =>'trim', + 'default' => '' + ) ); + register_setting( $this->plugin->name, self::WAA_CONF_TRACKER_DOMAIN, array( + 'sanitize_callback' => array(&$this->plugin->helpers, 'normalizeTrackerDomain'), + 'default' => 'https://stats.wideangle.co' + ) ); + register_setting( $this->plugin->name, self::WAA_CONF_IGNORE_HASH, array( + 'sanitize_callback' => array(&$this->plugin->helpers, 'normalizeBoolean'), + 'default' => 'false' + ) ); + register_setting( $this->plugin->name, self::WAA_CONF_GENERATED_HEADER_SCRIPT, array( + 'sanitize_callback' => 'trim', + 'default' => '' + ) ); + register_setting( $this->plugin->name, self::WAA_CONF_GENERATED_FOOTER_SCRIPT, array( + 'sanitize_callback' => 'trim', + 'default' => '' + ) ); + } + +} + +$waa = new WideAngleAnalytics(); // Plugin is initialized on contruction. +?>