Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions .github/actions/owa-server/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: OWA server
description: >-
Installs an OWA release (its packaged tarball) or branch (built the way OWA's
release workflow builds one) into the job's MySQL service as database "owa",
and serves it with php -S on 127.0.0.1:8080. Exports OWA_DIR, OWA_URL,
and serves it with php -S on 127.0.0.1:8080 as http://owa.test:8080/. Exports OWA_DIR, OWA_URL,
OWA_AUTH_KEY, OWA_API_KEY, OWA_SITE_ID and, with app-passwords, OWA_APP_PASSWORD.
inputs:
release:
Expand Down Expand Up @@ -62,13 +62,15 @@ runs:
-e "s#yournoncesaltgoeshere#$(openssl rand -hex 32)#" \
-e "s#yourauthkeygoeshere#$AUTH_KEY#" \
-e "s#yourauthsaltgoeshere#$(openssl rand -hex 32)#" \
-e "s#http://domain/path/to/owa/#http://127.0.0.1:8080/#" \
-e "s#http://domain/path/to/owa/#http://owa.test:8080/#" \
"$OWA_DIR/owa-config-dist.php" > "$OWA_DIR/owa-config.php"
# a name rather than an address, as screenshots and docs show it
echo "127.0.0.1 owa.test" | sudo tee -a /etc/hosts > /dev/null
mysql -h 127.0.0.1 -uroot -proot -e 'CREATE DATABASE IF NOT EXISTS owa'
(cd "$OWA_DIR" && php cli.php cmd=install user_id=admin email_address=admin@example.test domain="${{ inputs.domain }}")
q() { mysql -h 127.0.0.1 -uroot -proot owa -N -B -e "$1"; }
{
echo "OWA_URL=http://127.0.0.1:8080/"
echo "OWA_URL=http://owa.test:8080/"
echo "OWA_AUTH_KEY=$AUTH_KEY"
echo "OWA_API_KEY=$(q "SELECT api_key FROM owa_user WHERE user_id = 'admin'")"
echo "OWA_SITE_ID=$(q "SELECT site_id FROM owa_site LIMIT 1")"
Expand Down
Binary file added .wordpress-org/screenshot-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .wordpress-org/screenshot-2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .wordpress-org/screenshot-3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .wordpress-org/screenshot-4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .wordpress-org/screenshot-5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
56 changes: 24 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,47 +1,39 @@
# Open Web Analytics for WordPress Plugin
# Open Web Analytics for WordPress

The official plugin for integrating Open Web Analytics with WordPress based web sites and applications.
Adds Open Web Analytics (OWA) tracking to WordPress sites and multisite networks.

## Features
- OWA 1.x (API key) and 2.x (application password and tracking bundle, beta)
- Multisite network mode for OWA 2.x: one server and password for the network, an Observation Profile and tracking switch per site
- Fires `owa_wp_tag_changed` when a site's tag changes, so page caches can purge; Proxy Cache Purge does

- Track all public web pages
- Track WordPress admin interface pages
- Automatically sets page title
- Automatically sets page type
- Automatically sets user name of logged in users
Install it from [WordPress.org](https://wordpress.org/plugins/open-web-analytics/). Setup and options are on the [wiki](https://github.com/open-web-analytics/owa-wordpress-plugin/wiki).

## Requirements

* WordPress 5.2+
* PHP 8.2+
* An Open Web Analytics server, 1.14 or later (2.x in beta)
- WordPress 5.2+
- PHP 8.2+
- An OWA server, 1.14 or later

## Installation
## Development

The latest release of the plugin can be installed from the [WordPress plugin repository](https://wordpress.org/plugins/open-web-analytics/).
Requires Composer and Node 24.

## Development
```sh
composer install
npm ci
npm run build # the settings pages, into build/ (not committed)
composer test # PHP unit tests
npm run test:unit # JavaScript unit tests
```

To contribute to the Open Web Analytics for WordPress plugin you need to:
CI also runs integration tests against OWA 1.14 and 2.x, and browser tests (Playwright) on single-site and multisite WordPress. See `.github/workflows/ci.yml`.

1. Clone the repository
2. Download and install [Composer](https://getcomposer.org/) for managing PHP dependencies.
3. Run `composer install`
4. Run the tests with `composer test`
Publishing a GitHub release deploys to WordPress.org.

## Purchase or donate
## Donate

Open Web Analytics is free. However, we ask that you donate to the project if you need support. This donation helps fund the development of this project.
Open Web Analytics is free. If you need support, please [donate](http://paypal.me/openwebanalytics).

[Donate to the project here](http://paypal.me/openwebanalytics).
## License

## Documentation

Documentation for Open Web Analytics is maintained on the [wiki](https://github.com/open-web-analytics/owa-wordpress-plugin/wiki). Please feel free to add to the wiki if you use the plugin.


## Copyright and License

This project is licensed under the [GNU GPL](http://www.gnu.org/licenses/old-licenses/gpl-2.0.html), version 2 or later.

© [Peter Adams](http://peteradams.org).
[GNU GPL, version 2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.html). © [Peter Adams](http://peteradams.org).
97 changes: 68 additions & 29 deletions README.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,51 +2,90 @@

Contributors: padams
Donate link: http://paypal.me/openwebanalytics
Tags: web analytics, user tracking, clickstream, traffic analysis, traffic reporting, open web analytics, owa
License: GPLv3
License URI: http://www.gnu.org/licenses/gpl.html
Tags: web analytics, open web analytics, owa, traffic analysis, multisite
License: GPLv2
License URI: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
Requires at least: 5.2
Tested up to: 7.1
Requires PHP: 8.2
Stable tag: 2.3.0

The official plugin for integrating Open Web Analytics with WordPress based web sites and applications.
Adds Open Web Analytics tracking to WordPress sites and multisite networks.

== Description ==

Open Web Analytics is an open source alternative to commercial tools such as Google Analytics. Stay in control of the data you collect about the users of your website or app. This plugin does NOT install an instance of OWA server. It requires that you have admin access to a running instance of OWA, version 1.14 or later.
Adds the Open Web Analytics (OWA) tracking tag to your site's public pages. Requires an OWA server, 1.14 or later. The plugin does not install one.

OWA 2.x is supported in beta: set OWA Server Version to 2.x. The plugin then authenticates with an application password and adds your Website ID's tracking bundle, whose tracker settings you make on the OWA server.
= OWA 1.x and 2.x =

= FEATURES =
Choose the server version under OWA > Settings.

- Integrates your OWA instance with WordPress
- Track page views, visits actions etc.
- Automatically inserts tracking code on all published web pages (posts, pages, attachments, taxonomies, archives, etc.)
- Track WordPress admin interface pages
- Automatically sets page title
- Automatically sets page type
- Automatically sets user name of logged in users
* **1.x** authenticates with an OWA user's API key and the server's Secret Auth Key. Tracker options are set in WordPress.
* **2.x (beta)** authenticates with an OWA application password and loads the Observation Profile's tracking bundle. Tracker options are set on the OWA server; the settings page links to them.

= What is tracked =

* Public pages, with their title and page type.
* The user name of logged-in users, if Track Named Users is on.
* WordPress admin pages, if Track WP Admin Pages is on (1.x only).

Previews, the Customizer and, if Don't Track Logged-in Users is on, logged-in users are not tracked.

= Multisite =

With OWA 2.x, Network Admin > OWA sets one OWA server and application password for every site in the network. Then either:

* each site chooses its Observation Profile from those that share its domain, or
* the network sets each site's Observation Profile and turns tracking on or off per site.

= Page caches =

A cached page keeps the tracking tag it was rendered with. When a site's tag changes (tracking turned on or off, another Observation Profile or OWA server), the plugin fires `owa_wp_tag_changed` with the blog ID, in that site's context. Proxy Cache Purge purges the whole site on it. Other page caches can hook the same action.

== Installation ==

1. Install and activate the plugin.
2. Go to OWA > Settings.
3. Enter your OWA server's URL as the OWA Endpoint, ending with `/`.
4. Enter the credentials:
* 1.x: the API Key (OWA: Settings > Users > Edit) and the Secret Auth Key (`OWA_AUTH_KEY` in the server's `owa-config.php`).
* 2.x: select 2.x and enter an Application Password (OWA: My Preferences > Application Passwords). A read-only password is enough.
5. Save, then select the Observation Profile to track and save again. The plugin stores its site ID; in 1.x the field is labeled Website ID.

On a multisite network, set up OWA 2.x once under Network Admin > OWA.

== Frequently Asked Questions ==

= No tracking tag appears =

The tag is added once Enable OWA is on and the OWA Endpoint and Observation Profile are saved. Your theme must call `wp_head()`.

= The Observation Profiles do not load over http =

Application passwords are sent only over https. To use an http OWA server, turn off Application Passwords Need HTTPS on the OWA server, and set `allow_insecure_app_password` through the plugin's `owa_wp_sdk_config` filter:

`add_filter( 'owa_wp_sdk_config', fn( $config ) => [ 'allow_insecure_app_password' => true ] + $config );`

== Screenshots ==

1. Tracking Settings
1. Settings for OWA 1.x.
2. Settings for OWA 2.x.
3. Network Admin > OWA: each site's Observation Profile and tracking switch.
4. A site whose Observation Profile the network sets.
5. A site choosing from the Observation Profiles that share its domain.

== Changelog ==

= 2.3.0 =

* Beta support for OWA 2.x, chosen with the new OWA Server Version setting (1.x by default; nothing changes until you switch).
* Authenticates with an OWA application password instead of the API key and Secret Auth Key.
* Adds the Website ID's tracking bundle (public/tracker/<id>.js). Clicks, domstreams and the other tracker settings are made on the OWA server: the settings page links to the Website ID's Tracking Tag screen there.
* Tags public pages only. The page still sends its title, its page type and, if Track Named Users is on, the user name.
* Website IDs are listed with their Property's name.
* Multisite network mode (2.x): Network Admin > OWA takes the OWA endpoint and one application password for every site.
* Each site then chooses its Website ID from the Profiles that share its domain.
* Or the network configures each site's Profile in a mapping table, where each site starts on the Profile of exactly its domain. Opening the network settings page fetches the Profiles from OWA as it reads the network's sites, and marks new sites and new Profiles until the next save.
* In that mode each site also has a Tracking switch in the table; the network decides, and the site's own Enable OWA is hidden.
* New setting in both versions: Don't Track Logged-in Users.
* The settings pages are rebuilt with WordPress components (React). They save through the plugin's REST routes; keys and passwords are never sent back to the browser, and an invalid entry is reported under its field without saving anything.
* OWA 2.x support (beta), chosen with the new OWA Server Version setting. 1.x stays the default.
* Authenticates with an OWA application password.
* Loads the Observation Profile's tracking bundle. Tracker options are set on the OWA server; the settings page links to them.
* Tags public pages only.
* Multisite network mode (2.x): one OWA server and application password for the network. Each site chooses an Observation Profile that shares its domain, or the network sets each site's Observation Profile and tracking switch.
* Fires `owa_wp_tag_changed` when a site's tag changes. Proxy Cache Purge purges the site on it.
* New setting: Don't Track Logged-in Users.
* Settings pages rebuilt with WordPress components. Keys and passwords are never sent back to the browser. An invalid entry is reported under its field and nothing is saved.

= 2.2.3 =

Expand All @@ -73,8 +112,8 @@ OWA 2.x is supported in beta: set OWA Server Version to 2.x. The plugin then aut

== Development ==

This plugin is actively developed on [Github](https://github.com/open-web-analytics/owa-wordpress-plugin). Please file any bugs, feature, or support requests on Github!
Developed on [GitHub](https://github.com/open-web-analytics/owa-wordpress-plugin). File bugs and feature requests there.

== Donate! ==
== Donate ==

Open Web analytics is free. However, we ask that you [make a donation](http://paypal.me/openwebanalytics) if you require support or find this plugin useful!
Open Web Analytics is free. If you need support or find the plugin useful, please [donate](http://paypal.me/openwebanalytics).
13 changes: 0 additions & 13 deletions owa-plugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,6 @@
// Hook package creation
add_action('plugins_loaded', [ 'owaWp_plugin', 'getInstance' ], 10 );

// activation hook that checks for old version of plugin
register_activation_hook( __FILE__, ['owaWp_plugin', 'install'] );

/////////////////////////////////////////////////////////////////////////////////

require_once( OWA_WP_PLUGIN_PATH .'/vendor/autoload.php' );
Expand Down Expand Up @@ -98,16 +95,6 @@ function __construct() {
parent::__construct( $params );
}

public static function install() {

$old_plugin = 'owa/wp_plugin.php';

if ( is_plugin_active( $old_plugin ) ) {

deactivate_plugins( $old_plugin );
}
}

private function isProperWordPressRequest() {

// cron requests
Expand Down
1 change: 0 additions & 1 deletion tests/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ protected function setUp(): void {

Functions\stubs( [
'plugin_dir_path' => fn( $file ) => dirname( $file ) . '/',
'register_activation_hook' => null,
'wp_doing_cron' => false,
'esc_url_raw' => fn( $url ) => $url,
'wp_parse_url' => fn( $url, $component = -1 ) => parse_url( $url, $component ),
Expand Down
14 changes: 13 additions & 1 deletion tests/e2e/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,18 @@ async function shot( page, testInfo, name ) {
await page.screenshot( { path: path.join( dir, `${ name }.png` ), fullPage: true } );
}

/**
* A WordPress.org screenshot (.wordpress-org/screenshot-N.png): the admin
* page's content, without the menu and toolbar.
*/
async function docShot( page, number ) {
const dir = path.join( 'screenshots', 'wordpress-org' );
fs.mkdirSync( dir, { recursive: true } );
// the toolbar is fixed and the footer absolute: both would overlap the content
await page.addStyleTag( { content: '#wpadminbar, #wpfooter { display: none !important; }' } );
await page.locator( '#wpbody-content' ).screenshot( { path: path.join( dir, `screenshot-${ number }.png` ) } );
}

/** The OWA site ID (Profile) of a domain, from the OWA database. */
function owaSiteId( domain ) {
return execFileSync( 'mysql', [ '-h', '127.0.0.1', '-uroot', '-proot', 'owa', '-N', '-B', '-e',
Expand All @@ -58,4 +70,4 @@ function wp( ...args ) {
return execFileSync( 'wp', [ `--path=${ env( 'WP_DIR' ) }`, ...args ] ).toString();
}

module.exports = { env, login, notice, shot, owaSiteId, owaCli, wp };
module.exports = { env, docShot, login, notice, shot, owaSiteId, owaCli, wp };
7 changes: 6 additions & 1 deletion tests/e2e/multisite.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// a reload that brings in a new Profile and a new site, and both ways a site
// gets its Website ID.
const { test, expect } = require( '@playwright/test' );
const { env, login, notice, shot, owaSiteId, owaCli, wp } = require( './helpers' );
const { env, docShot, login, notice, shot, owaSiteId, owaCli, wp } = require( './helpers' );

const NETWORK_PAGE = 'http://wp.test/wp-admin/network/admin.php?page=owa-wordpress-network';

Expand Down Expand Up @@ -93,6 +93,9 @@ test( 'the network configures each site\'s Profile', async ( { page, browser },
await expect( row( page, 'a.wp.test' ) ).toHaveClass( /is-disabled/ );
await expect( row( page, 'a.wp.test' ) ).toContainText( `Site A – https://a.wp.test (${ siteA })` );
await shot( page, testInfo, '05b-site-switched-off' );
await page.reload();
await expect( tracking( page, 'a.wp.test' ) ).not.toBeChecked();
await docShot( page, 3 );

// the site shows what the network assigned, read-only, and none of the network's fields
await page.goto( 'http://a.wp.test/wp-admin/admin.php?page=owa-wordpress' );
Expand All @@ -106,6 +109,7 @@ test( 'the network configures each site\'s Profile', async ( { page, browser },
await expect( page.getByText( 'configures this site\'s Observation Profile and has tracking on this site turned off' ) ).toBeVisible();
await expect( page.getByLabel( 'Enable OWA' ) ).toHaveCount( 0 );
await shot( page, testInfo, '06-site-assigned' );
await docShot( page, 4 );

// visitors to b.wp.test get its bundle; a.wp.test is switched off, c.wp.test has no Profile
const visitor = await ( await browser.newContext() ).newPage();
Expand Down Expand Up @@ -140,4 +144,5 @@ test( 'each site picks from the Profiles sharing its domain', async ( { page },
expect( labels.some( ( v ) => v.includes( 'other.example' ) ) ).toBe( false );
await expect( page.getByText( 'The list shows the Observation Profiles that share this site\'s domain.' ) ).toBeVisible();
await shot( page, testInfo, '08-site-choice' );
await docShot( page, 5 );
} );
4 changes: 3 additions & 1 deletion tests/e2e/single.spec.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// A single-site WordPress: the 1.x / 2.x switch, 2.x settings with an
// application password, and the bundle tag on a public page.
const { test, expect } = require( '@playwright/test' );
const { env, login, notice, shot } = require( './helpers' );
const { env, docShot, login, notice, shot } = require( './helpers' );

test( 'switching to 2.x shows its fields, saves, and tags pages with the bundle', async ( { page, browser }, testInfo ) => {

Expand All @@ -23,6 +23,7 @@ test( 'switching to 2.x shows its fields, saves, and tags pages with the bundle'
await expect( notice( page, 'Open Web Analytics requires that you select a Website ID before tracking can begin.' ) ).toBeVisible();
await expect( page.locator( 'div.notice-warning' ) ).toHaveCount( 0 );
await shot( page, testInfo, '01-settings-1x' );
await docShot( page, 1 );

await tab( 'Tracking' ).click();
await expect( field( 'Track Clicks' ) ).toBeVisible();
Expand Down Expand Up @@ -89,6 +90,7 @@ test( 'switching to 2.x shows its fields, saves, and tags pages with the bundle'
await page.reload();
await expect( field( 'Observation Profile' ) ).toHaveValue( siteId );
await expect( field( 'Observation Profile' ).locator( 'option:checked' ) ).not.toHaveText( /not in the list from OWA/ );
await docShot( page, 2 );
expect( await page.content() ).not.toContain( env( 'OWA_APP_PASSWORD' ) );

// a visitor gets the bundle tag, and the bundle loads
Expand Down
Loading