From 732b4634878b30a1607fc5ea50b25164e7d03cab Mon Sep 17 00:00:00 2001 From: Dan0sz <18595395+Dan0sz@users.noreply.github.com> Date: Thu, 6 Mar 2025 15:28:20 +0100 Subject: [PATCH 01/44] Fixed: translation loaded too early in some configurations. --- src/Plugin.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Plugin.php b/src/Plugin.php index 2bbaa97e..865eb31a 100644 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -20,7 +20,7 @@ public function register() { add_action( 'plugins_loaded', [ $this, 'register_services' ], 9 ); // Load text domain. - add_action( 'init', [ $this, 'load_plugin_textdomain' ] ); + add_action( 'init', [ $this, 'load_plugin_textdomain' ], 1000 ); } /** From 2861484f26d768cd44fb5508ac0f530f13bf2127 Mon Sep 17 00:00:00 2001 From: Dan0sz <18595395+Dan0sz@users.noreply.github.com> Date: Fri, 7 Mar 2025 11:45:48 +0100 Subject: [PATCH 02/44] Updated tested with tag. --- readme.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.txt b/readme.txt index adfe0a11..a111499a 100644 --- a/readme.txt +++ b/readme.txt @@ -3,7 +3,7 @@ Contributors: plausible, DaanvandenBergh Donate link: https://plausible.io/ Tags: analytics, google analytics, web analytics, stats, privacy Requires at least: 5.9 -Tested up to: 6.6 +Tested up to: 6.7 Requires PHP: 7.0 Stable tag: 2.3.0 License: Massachusetts Institute of Technology (MIT) license From 9cfa9778ba580c344aab3b43a5675836a9714905 Mon Sep 17 00:00:00 2001 From: Dan0sz <18595395+Dan0sz@users.noreply.github.com> Date: Fri, 7 Mar 2025 11:47:11 +0100 Subject: [PATCH 03/44] Updated Tested Up To and Requires PHP tag. --- README.md | 74 ++++++++++++++++++++++++++++++++++++------------------ readme.txt | 2 +- 2 files changed, 50 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 5f7f40a0..3fa2171b 100644 --- a/README.md +++ b/README.md @@ -4,37 +4,45 @@ [![Github CI](https://github.com/plausible/wordpress/actions/workflows/push.yml/badge.svg)](https://github.com/plausible/wordpress/actions/workflows/push.yml) ![WordPress version](https://img.shields.io/wordpress/plugin/v/plausible-analytics.svg) ![WordPress Rating](https://img.shields.io/wordpress/plugin/r/plausible-analytics.svg) ![WordPress Downloads](https://img.shields.io/wordpress/plugin/dt/plausible-analytics.svg) -Welcome to the Plausible Analytics WordPress Plugin GitHub repository. This is the code source and the center of active development. Here you can +Welcome to the Plausible Analytics WordPress Plugin GitHub repository. This is the code source and the center of active +development. Here you can browse the source, look at open issues, and contribute to the project. ## Getting Started If you're looking to contribute or actively develop on Plausible Analytics then skip ahead to -the [Local Development](https://github.com/plausible/wordpress/#local-development) section below. The following is if you're looking to actively use +the [Local Development](https://github.com/plausible/wordpress/#local-development) section below. The following is if +you're looking to actively use the plugin on your WordPress site. ### Minimum Requirements -* WordPress 5.3 or greater +* WordPress 5.9 or greater * PHP version 7.4 or greater * MySQL version 5.5 or greater ### Automatic installation -Automatic installation is the easiest option as WordPress handles the file transfers itself, and you don't need to leave your web browser. To do an -automatic installation of Plausible Analytics, log in to your WordPress dashboard, navigate to the Plugins menu and click "Add New". +Automatic installation is the easiest option as WordPress handles the file transfers itself, and you don't need to leave +your web browser. To do an +automatic installation of Plausible Analytics, log in to your WordPress dashboard, navigate to the Plugins menu and +click "Add New". -In the search field type "Plausible Analytics" and click Search Plugins. Once you have found the plugin you can view details about it such as the +In the search field type "Plausible Analytics" and click Search Plugins. Once you have found the plugin you can view +details about it such as the point release, rating and description. Most importantly of course, you can install it by simply clicking "Install Now". ### Manual installation -The manual installation method involves downloading our plugin and uploading it to your server via your favorite FTP application. The -WordPress codex contains [instructions on how to do this](https://codex.wordpress.org/Managing_Plugins#Manual_Plugin_Installation). +The manual installation method involves downloading our plugin and uploading it to your server via your favorite FTP +application. The +WordPress codex +contains [instructions on how to do this](https://codex.wordpress.org/Managing_Plugins#Manual_Plugin_Installation). ### Support -This repository is not suitable for support. Please don't use GitHub issues for support requests. To get support please use the following channels: +This repository is not suitable for support. Please don't use GitHub issues for support requests. To get support please +use the following channels: * [WP.org Support Forums](https://wordpress.org/support/plugin/plausible-analytics) - for all users @@ -45,25 +53,33 @@ This repository is not suitable for support. Please don't use GitHub issues for - `plausible_analytics_settings`: Allows you to modify and/or force values for each of the plugin's settings. - `plausible_load_js_in_footer`: Allows you to load the JS code snippet in the footer. - `plausible_analytics_script_params`: Allows you to modify the `script` element, loading the Plausible JS library. - - Example: using this filter and the `file-types` attribute will allow you to track downloads of certain file types when File Downloads tracking is + - Example: using this filter and the `file-types` attribute will allow you to track downloads of certain file types + when File Downloads tracking is enabled. -- `plausible_analytics_pageview_properties`: Allows you to add custom pageview properties when the Pageview Properties option is enabled under - Enhanced Measurements. For examples, read the [documentation on Pageview Properties](https://plausible.io/docs/custom-props/for-pageviews). +- `plausible_analytics_pageview_properties`: Allows you to add custom pageview properties when the Pageview Properties + option is enabled under + Enhanced Measurements. For examples, read + the [documentation on Pageview Properties](https://plausible.io/docs/custom-props/for-pageviews). ### Actions - `plausible_analytics_settings_saved`: Trigger additional tasks directly after settings are saved. -- `plausible_analytics_after_register_assets`: This action allows you to trigger additional tasks or add custom JS (e.g. events) to the tracking code. +- `plausible_analytics_after_register_assets`: This action allows you to trigger additional tasks or add custom JS (e.g. + events) to the tracking code. ### Toggles -Using constants, you can modify the behavior of the plugin. `wp-config.php` is the best place to define constants. If you're using a custom plugin, +Using constants, you can modify the behavior of the plugin. `wp-config.php` is the best place to define constants. If +you're using a custom plugin, make sure its code is loaded before this plugin. -- `PLAUSIBLE_SELF_HOSTED_DOMAIN`: Especially useful for Multisite instances using the self-hosted version of Plausible, this constant allows you to - specify the Self-Hosted Domain for all subsites at once. **IMPORTANT**: this constant takes precedence over the plugin's setting. So, if this +- `PLAUSIBLE_SELF_HOSTED_DOMAIN`: Especially useful for Multisite instances using the self-hosted version of Plausible, + this constant allows you to + specify the Self-Hosted Domain for all subsites at once. **IMPORTANT**: this constant takes precedence over the + plugin's setting. So, if this constant is defined, changing the setting won't have any effect. -- `plausible_proxy`: Appending this `GET`-parameter will force enable the proxy on the page you\'re calling it. This will allow you to test your proxy +- `plausible_proxy`: Appending this `GET`-parameter will force enable the proxy on the page you\'re calling it. This + will allow you to test your proxy in the frontend, before enabling the option. ## Local Development @@ -83,7 +99,8 @@ That's it. You're now ready to start development. Plausible Analytics relies on several npm commands to get you started: -* `npm run watch` - Live reloads JS and SASS files. Typically, you'll run this command before you start development. It's necessary to build the +* `npm run watch` - Live reloads JS and SASS files. Typically, you'll run this command before you start development. + It's necessary to build the JS/CSS however if you're working strictly within PHP it may not be necessary to run. * `npm run dev` - Runs a one time build for development. No production files are created. @@ -91,7 +108,8 @@ Plausible Analytics relies on several npm commands to get you started: ### Development Notes -* Ensure that you have `SCRIPT_DEBUG` enabled within your wp-config.php file. Here's a good example of wp-config.php for debugging: +* Ensure that you have `SCRIPT_DEBUG` enabled within your wp-config.php file. Here's a good example of wp-config.php for + debugging: ``` // Enable WP_DEBUG mode define( 'WP_DEBUG', true ); @@ -103,21 +121,27 @@ Plausible Analytics relies on several npm commands to get you started: define( 'SCRIPT_DEBUG', true ); ``` * Commit the `package.lock` file. Read more about why [here](https://docs.npmjs.com/files/package-lock.json). -* Your editor should recognize the `.eslintrc` and `.editorconfig` files within the Repo's root directory. Please only submit PRs following those +* Your editor should recognize the `.eslintrc` and `.editorconfig` files within the Repo's root directory. Please only + submit PRs following those coding style rulesets. ### Regenerating the OpenAPI PHP Client -This plugin uses a OpenAPI PHP Client which is autogenerated by the OpenAPI generator to reduce contract violations, etc. to a minimum. But, since -this is a WordPress plugin, some manual modifications need to be done to make sure it doesn't conflict with other plugins: +This plugin uses a OpenAPI PHP Client which is autogenerated by the OpenAPI generator to reduce contract violations, +etc. to a minimum. But, since +this is a WordPress plugin, some manual modifications need to be done to make sure it doesn't conflict with other +plugins: -- (Re)generate the PHP client using the following command (trigger it from the Plugin's root dir as output will be saved to `src/Client`): +- (Re)generate the PHP client using the following command (trigger it from the Plugin's root dir as output will be saved + to `src/Client`): `openapi-generator-cli generate -i https://plausible.io/api/plugins/spec/openapi -g php -o src/Client --additional-properties=identifierNamingConvention=snake_case,invokerPackage="Plausible\\Analytics\\WP\\Client" --global-property=apis,models,supportingFiles,modelDocs=false,modelTests=false,apiDocs=false,apiTests=false` - (When regenerating the PHP client this step can be skipped) Navigate to the `src/Client` director and install Composer dependencies: `composer install --no-dev` -- (When regenerating the PHP client this step can be skipped) Run `mozart compose` from the `src/Client` directory (Make sure Mozart is installed +- (When regenerating the PHP client this step can be skipped) Run `mozart compose` from the `src/Client` directory (Make + sure Mozart is installed globally) -- In the `src/Client/lib` directory, replace all occurrences of ` GuzzleHttp` (mind the space) with ` Plausible\Analytics\WP\Client\Lib\GuzzleHttp` ( +- In the `src/Client/lib` directory, replace all occurrences of ` GuzzleHttp` (mind the space) with + ` Plausible\Analytics\WP\Client\Lib\GuzzleHttp` ( again, mind the space at the beginning) - In the same directory, replace all occurrences of ` \GuzzleHttp` (mind the space and backslash) with ` \Plausible\Analytics\WP\Client\Lib\GuzzleHttp`. diff --git a/readme.txt b/readme.txt index a111499a..3c02a3ae 100644 --- a/readme.txt +++ b/readme.txt @@ -4,7 +4,7 @@ Donate link: https://plausible.io/ Tags: analytics, google analytics, web analytics, stats, privacy Requires at least: 5.9 Tested up to: 6.7 -Requires PHP: 7.0 +Requires PHP: 7.2 Stable tag: 2.3.0 License: Massachusetts Institute of Technology (MIT) license License URI: https://opensource.org/licenses/MIT From a418ecccb694670e822859d60d9763096ca97538 Mon Sep 17 00:00:00 2001 From: Dan0sz <18595395+Dan0sz@users.noreply.github.com> Date: Tue, 11 Mar 2025 15:19:02 +0100 Subject: [PATCH 04/44] Added: support for add to cart tracking through direct links. --- src/Integrations/WooCommerce.php | 47 ++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/src/Integrations/WooCommerce.php b/src/Integrations/WooCommerce.php index eac2f576..2cae684a 100644 --- a/src/Integrations/WooCommerce.php +++ b/src/Integrations/WooCommerce.php @@ -69,8 +69,10 @@ private function init( $init ) { */ add_action( 'woocommerce_before_add_to_cart_quantity', [ $this, 'add_cart_form_hidden_input' ] ); add_action( 'woocommerce_after_add_to_cart_form', [ $this, 'track_add_to_cart_on_product_page' ] ); - add_filter( 'woocommerce_store_api_validate_add_to_cart', [ $this, 'track_add_to_cart' ], 10, 2 ); - add_filter( 'woocommerce_ajax_added_to_cart', [ $this, 'track_ajax_add_to_cart' ] ); + add_action( 'woocommerce_store_api_validate_add_to_cart', [ $this, 'track_add_to_cart' ], 10, 2 ); + add_action( 'woocommerce_ajax_added_to_cart', [ $this, 'track_ajax_add_to_cart' ] ); + /** @see \WC_Form_Handler::add_to_cart_action() runs on priority 20. */ + add_action( 'wp_loaded', [ $this, 'track_direct_add_to_cart' ], 21 ); add_action( 'woocommerce_remove_cart_item', [ $this, 'track_remove_cart_item' ], 10, 2 ); add_action( 'wp_head', [ $this, 'track_entered_checkout' ] ); add_action( 'woocommerce_thankyou', [ $this, 'track_purchase' ] ); @@ -173,22 +175,20 @@ public function track_add_to_cart_on_product_page() { } /** - * Track (non-Interactivity API, i.e. AJAX) add to cart events. - * - * @param string|int $product_id ID of the product added to the cart. + * Track add to cart actions by direct link, e.g. ?product_type=download&add-to-cart=1&quantity=1 * * @return void - * - * @codeCoverageIgnore Because we can't test XHR requests here. */ - public function track_ajax_add_to_cart( $product_id ) { - $product = wc_get_product( $product_id ); - $add_to_cart_data = [ - 'id' => $product_id, - 'quantity' => $_POST[ 'quantity' ] ?? 1, - ]; + public function track_direct_add_to_cart() { + if ( ! isset( $_REQUEST[ 'add-to-cart' ] ) || ! is_numeric( wp_unslash( $_REQUEST[ 'add-to-cart' ] ) ) ) { + return; + } - $this->track_add_to_cart( $product, $add_to_cart_data ); + $product_id = absint( wp_unslash( $_REQUEST[ 'add-to-cart' ] ) ); + $product = wc_get_product( $product_id ); + $quantity = isset( $_REQUEST[ 'quantity' ] ) ? absint( wp_unslash( $_REQUEST[ 'quantity' ] ) ) : 1; + + $this->track_add_to_cart( $product, [ 'id' => $product_id, 'quantity' => $quantity ] ); } /** @@ -241,6 +241,25 @@ private function clean_data( $product ) { return $product; } + /** + * Track (non-Interactivity API, i.e. AJAX) add to cart events. + * + * @param string|int $product_id ID of the product added to the cart. + * + * @return void + * + * @codeCoverageIgnore Because we can't test XHR requests here. + */ + public function track_ajax_add_to_cart( $product_id ) { + $product = wc_get_product( $product_id ); + $add_to_cart_data = [ + 'id' => $product_id, + 'quantity' => $_POST[ 'quantity' ] ?? 1, + ]; + + $this->track_add_to_cart( $product, $add_to_cart_data ); + } + /** * Track Remove from cart events. * From 44f3dea0a47790864a3d3a6b3e456e0c24bdc161 Mon Sep 17 00:00:00 2001 From: Dan0sz <18595395+Dan0sz@users.noreply.github.com> Date: Tue, 11 Mar 2025 15:19:24 +0100 Subject: [PATCH 05/44] Improved: if $url isn't set, and no referer is found, attempt to fallback to REQUEST_URI. --- src/Proxy.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Proxy.php b/src/Proxy.php index dd1c7dde..175f21dc 100644 --- a/src/Proxy.php +++ b/src/Proxy.php @@ -112,6 +112,16 @@ public function do_request( $name = 'pageview', $domain = '', $url = '', $props 'u' => $url ?: wp_get_referer(), ]; + // URL is required, so if no $url was set and no referer was found, attempt to create it from the REQUEST_URI server variable. + if ( empty( $body[ 'u' ] ) ) { + $parts = parse_url( $_SERVER[ 'REQUEST_URI' ] ); + $home_url_parts = parse_url( get_home_url() ); + + if ( isset( $home_url_parts[ 'scheme' ] ) && isset( $home_url_parts[ 'host' ] ) && isset( $parts[ 'path' ] ) ) { + $body[ 'u' ] = $home_url_parts[ 'scheme' ] . '://' . $home_url_parts [ 'host' ] . $parts[ 'path' ]; + } + } + // Revenue events use a different approach. if ( isset( $props[ 'revenue' ] ) ) { $body[ 'revenue' ] = reset( $props ); // @codeCoverageIgnore From 6ceaf40b2d68eacf365b6288495a343d76e5d882 Mon Sep 17 00:00:00 2001 From: Dan0sz <18595395+Dan0sz@users.noreply.github.com> Date: Thu, 13 Mar 2025 13:18:53 +0100 Subject: [PATCH 06/44] Minor re-factor to Cron label. --- src/Cron.php | 7 +++++++ src/Setup.php | 17 +++++------------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Cron.php b/src/Cron.php index 42120b90..8fb12269 100644 --- a/src/Cron.php +++ b/src/Cron.php @@ -13,6 +13,13 @@ use Exception; class Cron { + /** + * Cron job handle + * + * @var string + */ + const TASK_NAME = 'plausible_analytics_update_js'; + /** * Build class * diff --git a/src/Setup.php b/src/Setup.php index 45122b18..dd1f293a 100644 --- a/src/Setup.php +++ b/src/Setup.php @@ -10,13 +10,6 @@ namespace Plausible\Analytics\WP; class Setup { - /** - * Cron job handle - * - * @var string - */ - private $cron = 'plausible_analytics_update_js'; - /** * Filters and Hooks. * @@ -28,7 +21,7 @@ public function __construct() { register_deactivation_hook( PLAUSIBLE_ANALYTICS_PLUGIN_FILE, [ $this, 'deactivate_cron' ] ); // Attach the cron script to the cron action. - add_action( $this->cron, [ $this, 'load_cron_script' ] ); + add_action( Cron::TASK_NAME, [ $this, 'load_cron_script' ] ); // This assures that the local file is downloaded/updated when settings are saved. add_action( 'plausible_analytics_settings_saved', [ $this, 'load_cron_script' ] ); @@ -51,8 +44,8 @@ public function create_cache_dir() { * @codeCoverageIgnore */ public function activate_cron() { - if ( ! wp_next_scheduled( $this->cron ) ) { - wp_schedule_event( time(), 'daily', $this->cron ); + if ( ! wp_next_scheduled( Cron::TASK_NAME ) ) { + wp_schedule_event( time(), 'daily', Cron::TASK_NAME ); } } @@ -62,8 +55,8 @@ public function activate_cron() { * @codeCoverageIgnore */ public function deactivate_cron() { - if ( wp_next_scheduled( $this->cron ) ) { - wp_clear_scheduled_hook( $this->cron ); + if ( wp_next_scheduled( Cron::TASK_NAME ) ) { + wp_clear_scheduled_hook( Cron::TASK_NAME ); } } From 30e5769894c2757cbf852c7d427ae3639b2ad919 Mon Sep 17 00:00:00 2001 From: Dan0sz <18595395+Dan0sz@users.noreply.github.com> Date: Thu, 13 Mar 2025 13:37:13 +0100 Subject: [PATCH 07/44] Fixed: cron is now registered properly upon plugin activation. --- src/Plugin.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Plugin.php b/src/Plugin.php index 865eb31a..0d696488 100644 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -16,6 +16,8 @@ final class Plugin { * @return void */ public function register() { + $this->setup(); + // Register services used throughout the plugin. (WP Rocket runs at priority 10) add_action( 'plugins_loaded', [ $this, 'register_services' ], 9 ); @@ -23,6 +25,10 @@ public function register() { add_action( 'init', [ $this, 'load_plugin_textdomain' ], 1000 ); } + public function setup() { + new Setup(); + } + /** * Registers the individual services of the plugin. * @@ -47,7 +53,6 @@ public function register_services() { new Compatibility(); new Filters(); new Proxy(); - new Setup(); } /** From 18888d0d972606b2e2a73704171cc1493f7edb4a Mon Sep 17 00:00:00 2001 From: Dan0sz <18595395+Dan0sz@users.noreply.github.com> Date: Thu, 13 Mar 2025 13:50:47 +0100 Subject: [PATCH 08/44] PHPDoc. --- src/Plugin.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Plugin.php b/src/Plugin.php index 0d696488..bcd28afd 100644 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -25,6 +25,11 @@ public function register() { add_action( 'init', [ $this, 'load_plugin_textdomain' ], 1000 ); } + /** + * Register plugin (de)activation hooks and cron job. + * + * @return void + */ public function setup() { new Setup(); } From 8eb13c92b5bbfba960d4ac7bf4e6e940e0c7c15a Mon Sep 17 00:00:00 2001 From: Dan0sz <18595395+Dan0sz@users.noreply.github.com> Date: Thu, 13 Mar 2025 14:26:11 +0100 Subject: [PATCH 09/44] Ignore this function, because we can't test XHR requests here. --- src/Integrations/WooCommerce.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Integrations/WooCommerce.php b/src/Integrations/WooCommerce.php index 2cae684a..962983d6 100644 --- a/src/Integrations/WooCommerce.php +++ b/src/Integrations/WooCommerce.php @@ -178,6 +178,8 @@ public function track_add_to_cart_on_product_page() { * Track add to cart actions by direct link, e.g. ?product_type=download&add-to-cart=1&quantity=1 * * @return void + * + * @codeCoverageIgnore Because we can't test XHR here. */ public function track_direct_add_to_cart() { if ( ! isset( $_REQUEST[ 'add-to-cart' ] ) || ! is_numeric( wp_unslash( $_REQUEST[ 'add-to-cart' ] ) ) ) { From 5701c27f62ba11970da8755f733c2edf5878e513 Mon Sep 17 00:00:00 2001 From: Dan0sz <18595395+Dan0sz@users.noreply.github.com> Date: Thu, 13 Mar 2025 14:41:37 +0100 Subject: [PATCH 10/44] Added testGenerateEventUrl and refactored code for readability. --- src/Proxy.php | 24 ++++++++++++++++++------ tests/integration/ProxyTest.php | 29 +++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 6 deletions(-) create mode 100644 tests/integration/ProxyTest.php diff --git a/src/Proxy.php b/src/Proxy.php index 175f21dc..1012cbde 100644 --- a/src/Proxy.php +++ b/src/Proxy.php @@ -114,12 +114,7 @@ public function do_request( $name = 'pageview', $domain = '', $url = '', $props // URL is required, so if no $url was set and no referer was found, attempt to create it from the REQUEST_URI server variable. if ( empty( $body[ 'u' ] ) ) { - $parts = parse_url( $_SERVER[ 'REQUEST_URI' ] ); - $home_url_parts = parse_url( get_home_url() ); - - if ( isset( $home_url_parts[ 'scheme' ] ) && isset( $home_url_parts[ 'host' ] ) && isset( $parts[ 'path' ] ) ) { - $body[ 'u' ] = $home_url_parts[ 'scheme' ] . '://' . $home_url_parts [ 'host' ] . $parts[ 'path' ]; - } + $body[ 'u' ] = $this->generate_event_url(); // @codeCoverageIgnore } // Revenue events use a different approach. @@ -134,6 +129,23 @@ public function do_request( $name = 'pageview', $domain = '', $url = '', $props return $this->send_event( $request ); } + /** + * Attempts to generate the Event URL from available resources. + * + * @return string + */ + public function generate_event_url() { + $url = ''; + $parts = parse_url( $_SERVER[ 'REQUEST_URI' ] ); + $home_url_parts = parse_url( get_home_url() ); + + if ( isset( $home_url_parts[ 'scheme' ] ) && isset( $home_url_parts[ 'host' ] ) && isset( $parts[ 'path' ] ) ) { + $url = $home_url_parts[ 'scheme' ] . '://' . $home_url_parts [ 'host' ] . $parts[ 'path' ]; + } + + return $url; + } + /** * Formats and sends $request to the Plausible API. * diff --git a/tests/integration/ProxyTest.php b/tests/integration/ProxyTest.php new file mode 100644 index 00000000..b955368b --- /dev/null +++ b/tests/integration/ProxyTest.php @@ -0,0 +1,29 @@ +generate_event_url(); + + $this->assertEquals( 'http://example.org', $url ); + + $_SERVER[ 'REQUEST_URI' ] = '/test'; + + $url = $proxy->generate_event_url(); + + $this->assertEquals( 'http://example.org/test', $url ); + } +} From 1b86992071f0bffee45ffd661d0bd010d36f19c1 Mon Sep 17 00:00:00 2001 From: Dan0sz <18595395+Dan0sz@users.noreply.github.com> Date: Thu, 13 Mar 2025 14:43:07 +0100 Subject: [PATCH 11/44] Moved ClientFactoryTest to Integration tests and removed Unit tests dir. --- tests/{unit => integration}/ClientFactoryTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename tests/{unit => integration}/ClientFactoryTest.php (92%) diff --git a/tests/unit/ClientFactoryTest.php b/tests/integration/ClientFactoryTest.php similarity index 92% rename from tests/unit/ClientFactoryTest.php rename to tests/integration/ClientFactoryTest.php index 74486046..01413679 100644 --- a/tests/unit/ClientFactoryTest.php +++ b/tests/integration/ClientFactoryTest.php @@ -3,7 +3,7 @@ * @package Plausible Analytics Unit Tests - ClientFactory */ -namespace Plausible\Analytics\Tests\Unit; +namespace Plausible\Analytics\Tests\Integration; use Plausible\Analytics\Tests\TestCase; use Plausible\Analytics\WP\Client; From 56e7b495a55c3554296c064eb0569480345e60d3 Mon Sep 17 00:00:00 2001 From: Dan0sz <18595395+Dan0sz@users.noreply.github.com> Date: Thu, 13 Mar 2025 15:44:21 +0100 Subject: [PATCH 12/44] Improved: added Gravity Forms compatibility for Form Completions. --- src/Integrations/FormSubmit.php | 52 ++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/src/Integrations/FormSubmit.php b/src/Integrations/FormSubmit.php index b74d0561..89a9a99a 100644 --- a/src/Integrations/FormSubmit.php +++ b/src/Integrations/FormSubmit.php @@ -33,6 +33,10 @@ private function init() { * Contact Form 7 doesn't respect JS checkValidity() function, so this is a custom compatibility fix. */ add_filter( 'wpcf7_validate', [ $this, 'maybe_track_submission' ], 10, 2 ); + /** + * Gravity Forms contains its own form submission handler, so this is a custom compatibility fix. + */ + add_action( 'gform_after_submission', [ $this, 'track_gravity_forms_submission' ], 10 ); } /** @@ -60,10 +64,13 @@ public function add_js() { /** * Tracks the form submission if CF7 says it's valid. * + * @filter wpcf7_validate + * * @param \WPCF7_Validation $result Form submission result object containing validation results. * @param array $tags Array of tags associated with the form fields. * * @return \WPCF7_Validation + * * @codeCoverageIgnore because we can't test XHR requests here. */ public function maybe_track_submission( $result, $tags ) { @@ -73,15 +80,46 @@ public function maybe_track_submission( $result, $tags ) { $post = get_post( $_POST[ '_wpcf7_container_post' ] ); $uri = '/' . $post->post_name . '/'; - $proxy = new Proxy( false ); - $proxy->do_request( - __( 'WP Form Completions', 'plausible-analytics' ), - null, - null, - [ 'path' => $uri ] - ); + $this->track_submission( $uri ); } return $result; } + + /** + * Track submission using the Proxy. + * + * @param $uri + * + * @return void + */ + private function track_submission( $uri ) { + $proxy = new Proxy( false ); + $proxy->do_request( + __( 'WP Form Completions', 'plausible-analytics' ), + null, + null, + [ 'path' => $uri ] + ); + } + + /** + * Compatibility fix for Gravity Forms. + * + * @action gform_after_submission + * + * @param $form + * @param $entry + * + * @return void + */ + public function track_gravity_forms_submission( $form ) { + $uri = str_replace( home_url(), '', $form[ 'source_url' ] ) ?? ''; + + if ( empty( $uri ) ) { + return; + } + + $this->track_submission( $uri ); + } } From 8a8d705164554b86c5128dfe9209b91045098866 Mon Sep 17 00:00:00 2001 From: Dan0sz <18595395+Dan0sz@users.noreply.github.com> Date: Thu, 13 Mar 2025 15:46:29 +0100 Subject: [PATCH 13/44] Ignore code. --- src/Integrations/FormSubmit.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Integrations/FormSubmit.php b/src/Integrations/FormSubmit.php index 89a9a99a..1bc8d821 100644 --- a/src/Integrations/FormSubmit.php +++ b/src/Integrations/FormSubmit.php @@ -13,6 +13,7 @@ class FormSubmit { /** * Build class. + * * @codeCoverageIgnore */ public function __construct() { @@ -21,7 +22,9 @@ public function __construct() { /** * Init + * * @return void + * * @codeCoverageIgnore */ private function init() { @@ -42,6 +45,7 @@ private function init() { /** * Enqueues the required JavaScript for form submissions integration. * @return void + * * @codeCoverageIgnore because there's nothing to test here. */ public function add_js() { @@ -92,9 +96,12 @@ public function maybe_track_submission( $result, $tags ) { * @param $uri * * @return void + * + * @codeCoverageIgnore because we can't test XHR requests here. */ private function track_submission( $uri ) { $proxy = new Proxy( false ); + $proxy->do_request( __( 'WP Form Completions', 'plausible-analytics' ), null, @@ -106,12 +113,14 @@ private function track_submission( $uri ) { /** * Compatibility fix for Gravity Forms. * - * @action gform_after_submission + * @action gform_after_submission * * @param $form * @param $entry * * @return void + * + * @codeCoverageIgnore because we can't test XHR requests here. */ public function track_gravity_forms_submission( $form ) { $uri = str_replace( home_url(), '', $form[ 'source_url' ] ) ?? ''; From 64d505e8f7b2c0579634e90791bd4dec3f956b38 Mon Sep 17 00:00:00 2001 From: Dan0sz <18595395+Dan0sz@users.noreply.github.com> Date: Thu, 13 Mar 2025 16:39:54 +0100 Subject: [PATCH 14/44] Added: upgrade script for 2.3.1 and tests. --- src/Admin/Upgrades.php | 18 ++++++++++++++++++ tests/integration/Admin/UpgradesTest.php | 12 ++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/Admin/Upgrades.php b/src/Admin/Upgrades.php index 5639cf76..6df274f5 100644 --- a/src/Admin/Upgrades.php +++ b/src/Admin/Upgrades.php @@ -13,6 +13,7 @@ use Plausible\Analytics\WP\Admin\Provisioning\Integrations; use Plausible\Analytics\WP\Client; use Plausible\Analytics\WP\Helpers; +use Plausible\Analytics\WP\Setup; /** * Class Upgrades @@ -83,6 +84,10 @@ public function run() { $this->upgrade_to_230(); } + if ( version_compare( $plausible_analytics_version, '2.3.1', '<' ) ) { + $this->upgrade_to_231(); + } + // Add required upgrade routines for future versions here. } @@ -304,4 +309,17 @@ public function upgrade_to_230() { update_option( 'plausible_analytics_version', '2.3.0' ); } + + /** + * Make sure the cron event is scheduled. If it's already scheduled or the Proxy isn't enabled, it'll bail. + * + * @return void + */ + public function upgrade_to_231() { + $setup = new Setup(); + + $setup->activate_cron(); + + update_option( 'plausible_analytics_version', '2.3.1' ); + } } diff --git a/tests/integration/Admin/UpgradesTest.php b/tests/integration/Admin/UpgradesTest.php index 183cee27..4227c976 100644 --- a/tests/integration/Admin/UpgradesTest.php +++ b/tests/integration/Admin/UpgradesTest.php @@ -7,6 +7,7 @@ use Plausible\Analytics\Tests\TestCase; use Plausible\Analytics\WP\Admin\Upgrades; +use Plausible\Analytics\WP\Cron; use Plausible\Analytics\WP\Helpers; class UpgradesTest extends TestCase { @@ -27,4 +28,15 @@ public function testUpgradeTo210() { $this->assertIsArray( $enhanced_measurements ); } + + /** + * @see Upgrades::upgrade_to_231() + * @return void + */ + public function testUpgradeTo231() { + $class = new Upgrades(); + $class->upgrade_to_231(); + + $this->assertNotEmpty( wp_next_scheduled( Cron::TASK_NAME ) ); + } } From e1b25a1a45874a84e354fd89ef203a4553c747ab Mon Sep 17 00:00:00 2001 From: Marko Saric <34340819+metmarkosaric@users.noreply.github.com> Date: Fri, 14 Mar 2025 10:23:07 +0100 Subject: [PATCH 15/44] Update readme.txt --- readme.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.txt b/readme.txt index 3c02a3ae..781e602e 100644 --- a/readme.txt +++ b/readme.txt @@ -29,7 +29,7 @@ We're completely independent, self-funded, bootstrapped and debt-free. We're not Google Analytics is frustrating to use, difficult to understand, slow to load and privacy-invasive. That's why we built Plausible Analytics, a simple but powerful, lightweight, open source and privacy-friendly alternative. -Here's what makes Plausible a great Google Analytics alternative and why over 14,000 paying subscribers trust us with their website and business insights: +Here's what makes Plausible a great Google Analytics alternative and why over 15,000 paying subscribers trust us with their website and business insights: ### Smooth transition from Google Analytics @@ -49,7 +49,7 @@ Plausible is privacy-friendly analytics. All the site measurement is carried out ### Track events and marketing campaigns -Plausible is useful. Segment your audience by any metric you click on. Answer the important questions about your visitors, content and referral sources. Analyze paid campaigns using UTM parameters. Track site search terms, outbound link clicks, file downloads, form completions, 404 error pages, post authors, post categories and custom taxonomies without manually configuring anything or writing any code. +Plausible is useful. Segment your audience by any metric you click on. Answer the important questions about your visitors, content and referral sources. Analyze paid campaigns using UTM parameters. Track scroll depth, site search terms, outbound link clicks, file downloads, form completions, 404 error pages, post authors, post categories and custom taxonomies without manually configuring anything or writing any code. ### Built-in WooCommerce and Easy Digital Downloads analytics From 4adfa527936b012a6f167b2c39b2fbe56818ddb4 Mon Sep 17 00:00:00 2001 From: Dan0sz <18595395+Dan0sz@users.noreply.github.com> Date: Fri, 14 Mar 2025 14:26:45 +0100 Subject: [PATCH 16/44] Fixed: run track_direct_add_to_cart before WC's add to cart action in case it triggers a redirect. --- src/Integrations/WooCommerce.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Integrations/WooCommerce.php b/src/Integrations/WooCommerce.php index 962983d6..9eec455b 100644 --- a/src/Integrations/WooCommerce.php +++ b/src/Integrations/WooCommerce.php @@ -71,8 +71,8 @@ private function init( $init ) { add_action( 'woocommerce_after_add_to_cart_form', [ $this, 'track_add_to_cart_on_product_page' ] ); add_action( 'woocommerce_store_api_validate_add_to_cart', [ $this, 'track_add_to_cart' ], 10, 2 ); add_action( 'woocommerce_ajax_added_to_cart', [ $this, 'track_ajax_add_to_cart' ] ); - /** @see \WC_Form_Handler::add_to_cart_action() runs on priority 20. */ - add_action( 'wp_loaded', [ $this, 'track_direct_add_to_cart' ], 21 ); + /** @see \WC_Form_Handler::add_to_cart_action() runs on priority 20. We need to run before that, in case redirect is enabled. */ + add_action( 'wp_loaded', [ $this, 'track_direct_add_to_cart' ], 19 ); add_action( 'woocommerce_remove_cart_item', [ $this, 'track_remove_cart_item' ], 10, 2 ); add_action( 'wp_head', [ $this, 'track_entered_checkout' ] ); add_action( 'woocommerce_thankyou', [ $this, 'track_purchase' ] ); From ca23f2f76b341afa06e4a8a6473f6ce9894e1a05 Mon Sep 17 00:00:00 2001 From: Dan0sz <18595395+Dan0sz@users.noreply.github.com> Date: Fri, 14 Mar 2025 14:36:56 +0100 Subject: [PATCH 17/44] Only change JS ID if IE compatibility is enabled. --- src/Filters.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Filters.php b/src/Filters.php index 8255123e..ac79eb29 100644 --- a/src/Filters.php +++ b/src/Filters.php @@ -51,8 +51,11 @@ public function add_plausible_attributes( $tag, $handle ) { $api_url = Helpers::get_data_api_url(); $domain_name = Helpers::get_domain(); - // We need the correct id attribute for IE compatibility. - $tag = preg_replace( "/\sid=(['\"])plausible-analytics-js(['\"])/", " id=$1plausible$2", $tag ); + if ( Helpers::is_enhanced_measurement_enabled( 'compat' ) ) { + // We need the correct id attribute for IE compatibility. + $tag = preg_replace( "/\sid=(['\"])plausible-analytics-js(['\"])/", " id=$1plausible$2", $tag ); + } + /** * the data-cfasync ensures this script isn't processed by CF Rocket Loader @see https://developers.cloudflare.com/speed/optimization/content/rocket-loader/ignore-javascripts/ */ From 08f583a2876a43177ccbee3bd45a08ac76f89fc7 Mon Sep 17 00:00:00 2001 From: Dan0sz <18595395+Dan0sz@users.noreply.github.com> Date: Fri, 14 Mar 2025 14:46:24 +0100 Subject: [PATCH 18/44] Updated FiltersTest --- tests/TestCase.php | 13 +++++++++++++ tests/integration/FiltersTest.php | 9 +++++++++ 2 files changed, 22 insertions(+) diff --git a/tests/TestCase.php b/tests/TestCase.php index 084027d1..83cf3c26 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -36,6 +36,19 @@ public function enableRevenue( $settings ) { return $settings; } + /** + * Enable Enhanced Measurements > IE Compatibility + * + * @param $settings + * + * @return mixed + */ + public function enableCompat( $settings ) { + $settings[ 'enhanced_measurements' ] = [ 'compat' ]; + + return $settings; + } + /** * Enable form completions by modifying the settings array. * diff --git a/tests/integration/FiltersTest.php b/tests/integration/FiltersTest.php index ac99f5c4..e448126b 100644 --- a/tests/integration/FiltersTest.php +++ b/tests/integration/FiltersTest.php @@ -18,6 +18,15 @@ public function testAddPlausibleAttributes() { $this->assertStringContainsString( 'example.org', $tag ); $this->assertStringContainsString( 'plausible.io/api/event', $tag ); + $this->assertStringContainsString( 'plausible-analytics-js', $tag ); + + add_filter( 'plausible_analytics_settings', [ $this, 'enableCompat' ] ); + + $class = new Filters(); + $tag = $class->add_plausible_attributes( '