| 1 |
<?php |
| 2 |
/** |
| 3 |
* Ebook Store - "Google Analytics" settings tab. |
| 4 |
* |
| 5 |
* Connects the store to Google Analytics 4: browser events from the measurement |
| 6 |
* ID, plus confirmed purchase and refund events from the Measurement Protocol |
| 7 |
* API secret. |
| 8 |
* |
| 9 |
* PHP 7.4 compatible. |
| 10 |
* |
| 11 |
* @package EbookStore |
| 12 |
*/ |
| 13 |
|
| 14 |
if ( ! defined( 'ABSPATH' ) ) { |
| 15 |
exit; |
| 16 |
} |
| 17 |
|
| 18 |
settings_fields( 'ebook-settings-group-google-analytics' ); |
| 19 |
do_settings_sections( 'ebook-settings-group-google-analytics' ); |
| 20 |
|
| 21 |
$ga4_enabled = (string) get_option( 'ebook_store_google_analytics_enabled', '' ); |
| 22 |
$ga4_measurement_id = trim( (string) get_option( 'ebook_store_google_analytics_measurement_id', '' ) ); |
| 23 |
$ga4_api_secret = trim( (string) get_option( 'ebook_store_google_analytics_api_secret', '' ) ); |
| 24 |
$ga4_id_looks_valid = ( $ga4_measurement_id === '' || stripos( $ga4_measurement_id, 'G-' ) === 0 ); |
| 25 |
$general_tab_url = ebook_store_get_settings_tab_url( 'General' ); |
| 26 |
|
| 27 |
ebook_store_pro_banner( __( 'Google Analytics', 'ebook-store' ) ); |
| 28 |
|
| 29 |
ebook_store_render_hero( |
| 30 |
array( |
| 31 |
'eyebrow' => __( 'Google Analytics', 'ebook-store' ), |
| 32 |
'title' => __( 'See what your ebooks do in Google Analytics 4', 'ebook-store' ), |
| 33 |
'intro' => __( 'Ebook Store can tell Google Analytics when a book page is viewed, when a buyer starts checkout, when a payment is confirmed, and when an order is later refunded. You need a Google Analytics 4 property before you start.', 'ebook-store' ), |
| 34 |
'aside' => function () use ( $ga4_enabled, $ga4_measurement_id, $ga4_api_secret ) { |
| 35 |
$license = ebook_store_get_license_summary(); |
| 36 |
?> |
| 37 |
<aside class="ebook-settings-status-card"> |
| 38 |
<h4><?php echo esc_html__( 'Current status', 'ebook-store' ); ?></h4> |
| 39 |
<ul class="ebook-settings-status-list"> |
| 40 |
<?php |
| 41 |
ebook_store_status_row( |
| 42 |
__( 'Tracking', 'ebook-store' ), |
| 43 |
$ga4_enabled === '1' ? 'ok' : 'muted', |
| 44 |
$ga4_enabled === '1' |
| 45 |
? __( 'Switched on for this store.', 'ebook-store' ) |
| 46 |
: __( 'Switched off. Nothing is sent to Google Analytics.', 'ebook-store' ) |
| 47 |
); |
| 48 |
|
| 49 |
ebook_store_status_row( |
| 50 |
__( 'Measurement ID', 'ebook-store' ), |
| 51 |
$ga4_measurement_id !== '' ? 'ok' : 'warn', |
| 52 |
$ga4_measurement_id !== '' |
| 53 |
? sprintf( |
| 54 |
/* translators: %s: the saved GA4 measurement ID, for example G-AB12CD34EF. */ |
| 55 |
__( 'Saved as %s. Browser events can be sent.', 'ebook-store' ), |
| 56 |
$ga4_measurement_id |
| 57 |
) |
| 58 |
: __( 'Not set yet. Without it nothing at all is tracked.', 'ebook-store' ) |
| 59 |
); |
| 60 |
|
| 61 |
ebook_store_status_row( |
| 62 |
__( 'API secret', 'ebook-store' ), |
| 63 |
$ga4_api_secret !== '' ? 'ok' : 'muted', |
| 64 |
$ga4_api_secret !== '' |
| 65 |
? __( 'Saved. Confirmed purchases and refunds are reported too.', 'ebook-store' ) |
| 66 |
: __( 'Not set. Optional, but purchases and refunds will be missing.', 'ebook-store' ) |
| 67 |
); |
| 68 |
|
| 69 |
ebook_store_status_row( |
| 70 |
$license['label'], |
| 71 |
$license['tone'], |
| 72 |
$license['message'] |
| 73 |
); |
| 74 |
?> |
| 75 |
</ul> |
| 76 |
</aside> |
| 77 |
<?php |
| 78 |
}, |
| 79 |
) |
| 80 |
); |
| 81 |
|
| 82 |
ebook_store_section_open( |
| 83 |
array( |
| 84 |
'eyebrow' => __( 'Step 1', 'ebook-store' ), |
| 85 |
'title' => __( 'Turn tracking on', 'ebook-store' ), |
| 86 |
'intro' => __( 'Nothing is sent to Google until this switch is on and a measurement ID is saved below.', 'ebook-store' ), |
| 87 |
'id' => 'ebook-ga4-enable', |
| 88 |
'pro' => true, |
| 89 |
) |
| 90 |
); |
| 91 |
|
| 92 |
ebook_store_toggle_grid_open(); |
| 93 |
|
| 94 |
ebook_store_toggle( |
| 95 |
array( |
| 96 |
'name' => 'ebook_store_google_analytics_enabled', |
| 97 |
'title' => __( 'Send Ebook Store activity to Google Analytics 4', 'ebook-store' ), |
| 98 |
'description' => __( 'Adds the Google tag to your ebook pages and reports confirmed orders and refunds from your server.', 'ebook-store' ), |
| 99 |
'checked' => $ga4_enabled, |
| 100 |
'pro' => true, |
| 101 |
) |
| 102 |
); |
| 103 |
|
| 104 |
ebook_store_toggle_grid_close(); |
| 105 |
|
| 106 |
ebook_store_callout( |
| 107 |
sprintf( |
| 108 |
/* translators: %s: link to the General settings tab. */ |
| 109 |
__( 'Google Analytics tracking is part of Ebook Store Pro. It only runs once a license key is saved on the <a href="%s">General tab</a>.', 'ebook-store' ), |
| 110 |
esc_url( $general_tab_url ) |
| 111 |
), |
| 112 |
'info', |
| 113 |
__( 'Requires Pro:', 'ebook-store' ) |
| 114 |
); |
| 115 |
|
| 116 |
ebook_store_section_close(); |
| 117 |
|
| 118 |
ebook_store_section_open( |
| 119 |
array( |
| 120 |
'eyebrow' => __( 'Step 2', 'ebook-store' ), |
| 121 |
'title' => __( 'Your two Google credentials', 'ebook-store' ), |
| 122 |
'intro' => __( 'The measurement ID is required. The API secret is optional and only needed for confirmed purchase and refund reporting.', 'ebook-store' ), |
| 123 |
'id' => 'ebook-ga4-credentials', |
| 124 |
'pro' => true, |
| 125 |
) |
| 126 |
); |
| 127 |
|
| 128 |
ebook_store_steps( |
| 129 |
__( 'Where to find these in Google Analytics', 'ebook-store' ), |
| 130 |
array( |
| 131 |
__( 'Sign in to Google Analytics and open Admin, then Data streams, then click the stream for this website.', 'ebook-store' ), |
| 132 |
__( 'The measurement ID is shown at the top right of that screen. It starts with G- followed by letters and numbers. Copy it and paste it in the first box below.', 'ebook-store' ), |
| 133 |
__( 'Only if you want purchases and refunds reported: on the same screen open Measurement Protocol API secrets, click Create, give it any nickname, and copy the secret value it shows you.', 'ebook-store' ), |
| 134 |
__( 'Paste that secret in the second box below, then click Save Changes.', 'ebook-store' ), |
| 135 |
) |
| 136 |
); |
| 137 |
|
| 138 |
ebook_store_grid_open( 2 ); |
| 139 |
|
| 140 |
ebook_store_field( |
| 141 |
array( |
| 142 |
'type' => 'text', |
| 143 |
'name' => 'ebook_store_google_analytics_measurement_id', |
| 144 |
'label' => __( 'Measurement ID (required)', 'ebook-store' ), |
| 145 |
'value' => $ga4_measurement_id, |
| 146 |
'placeholder' => 'G-XXXXXXXXXX', |
| 147 |
'wide' => true, |
| 148 |
'mono' => true, |
| 149 |
'pro' => true, |
| 150 |
'help' => __( 'This is the code that identifies your website inside Google Analytics, for example G-AB12CD34EF. It powers everything that happens in the buyer\'s browser: book page views, payment method clicks and checkout starts. If you paste the ID of the wrong property, your sales data will land in someone else\'s reports. If you leave it empty, nothing is tracked at all.', 'ebook-store' ), |
| 151 |
'note' => $ga4_id_looks_valid ? '' : __( 'This does not look like a measurement ID. Google measurement IDs begin with G-. A number that begins with UA- belongs to the old Universal Analytics and no longer works.', 'ebook-store' ), |
| 152 |
'note_tone' => $ga4_id_looks_valid ? 'neutral' : 'warning', |
| 153 |
) |
| 154 |
); |
| 155 |
|
| 156 |
ebook_store_grid_close(); |
| 157 |
|
| 158 |
ebook_store_advanced_open( __( 'Advanced: purchase and refund reporting', 'ebook-store' ) ); |
| 159 |
|
| 160 |
ebook_store_grid_open( 2 ); |
| 161 |
|
| 162 |
ebook_store_field( |
| 163 |
array( |
| 164 |
'type' => 'password', |
| 165 |
'name' => 'ebook_store_google_analytics_api_secret', |
| 166 |
'label' => __( 'API secret (optional)', 'ebook-store' ), |
| 167 |
'value' => $ga4_api_secret, |
| 168 |
'placeholder' => __( 'Only needed for purchase and refund events', 'ebook-store' ), |
| 169 |
'wide' => true, |
| 170 |
'mono' => true, |
| 171 |
'pro' => true, |
| 172 |
'help' => __( 'A separate key created in the same data stream, under Measurement Protocol API secrets. Your server uses it to tell Google about a sale <strong>after</strong> the payment is really confirmed, and about a refund when you cancel an order. If you only want page views and checkout starts, you can leave this empty. If it is wrong or missing, everything else keeps working, but no purchase or refund will ever show up in your reports.', 'ebook-store' ), |
| 173 |
) |
| 174 |
); |
| 175 |
|
| 176 |
ebook_store_grid_close(); |
| 177 |
|
| 178 |
ebook_store_callout( |
| 179 |
__( 'Treat the API secret like a password. Anyone who has it can write fake data into your Analytics property, so do not paste it into support tickets or public forums.', 'ebook-store' ), |
| 180 |
'warning', |
| 181 |
__( 'Keep it private:', 'ebook-store' ) |
| 182 |
); |
| 183 |
|
| 184 |
ebook_store_advanced_close(); |
| 185 |
|
| 186 |
ebook_store_section_close(); |
| 187 |
|
| 188 |
ebook_store_section_open( |
| 189 |
array( |
| 190 |
'eyebrow' => __( 'Reference', 'ebook-store' ), |
| 191 |
'title' => __( 'What gets sent, and when', 'ebook-store' ), |
| 192 |
'intro' => __( 'These are the standard Google Analytics ecommerce events. The first three happen in the visitor\'s browser, the last two are sent from your server, so they only work once an API secret is saved.', 'ebook-store' ), |
| 193 |
'id' => 'ebook-ga4-events', |
| 194 |
) |
| 195 |
); |
| 196 |
|
| 197 |
ebook_store_advanced_open( __( 'Show the full event reference', 'ebook-store' ) ); |
| 198 |
?> |
| 199 |
|
| 200 |
<ul class="ebook-settings-event-list" style="margin:8px 0 0 18px; list-style:disc;"> |
| 201 |
<li> |
| 202 |
<code>view_item</code> |
| 203 |
— <?php echo esc_html__( 'Fires when a visitor opens a page that shows one of your ebooks through an Ebook Store shortcode. Needs the measurement ID only.', 'ebook-store' ); ?> |
| 204 |
</li> |
| 205 |
<li> |
| 206 |
<code>add_payment_info</code> |
| 207 |
— <?php echo esc_html__( 'Fires when the buyer picks a payment method, on templates that show several methods side by side. Needs the measurement ID only.', 'ebook-store' ); ?> |
| 208 |
</li> |
| 209 |
<li> |
| 210 |
<code>begin_checkout</code> |
| 211 |
— <?php echo esc_html__( 'Fires the moment the buyer clicks the buy button and leaves for PayPal, Stripe, Adyen or WooCommerce. Needs the measurement ID only.', 'ebook-store' ); ?> |
| 212 |
</li> |
| 213 |
<li> |
| 214 |
<code>purchase</code> |
| 215 |
— <?php echo esc_html__( 'Sent from your server only after the payment is confirmed and the order is saved, never on the mere return from the payment page. Needs the API secret.', 'ebook-store' ); ?> |
| 216 |
</li> |
| 217 |
<li> |
| 218 |
<code>refund</code> |
| 219 |
— <?php echo esc_html__( 'Sent from your server when a paid order is later marked refunded, cancelled, reversed, denied or failed. Needs the API secret.', 'ebook-store' ); ?> |
| 220 |
</li> |
| 221 |
</ul> |
| 222 |
|
| 223 |
<?php |
| 224 |
ebook_store_callout( |
| 225 |
__( 'Because a purchase is only counted after the payment is confirmed, your Analytics revenue will usually be a little lower than the number of checkout starts. That difference is buyers who abandoned the payment page, not a tracking fault. Each order is reported once, so refreshing a thank-you page cannot double-count a sale.', 'ebook-store' ), |
| 226 |
'soft', |
| 227 |
__( 'Reading the numbers:', 'ebook-store' ) |
| 228 |
); |
| 229 |
|
| 230 |
ebook_store_callout( |
| 231 |
__( 'Free downloads, bonus downloads and orders with a zero total are deliberately not reported as purchases, so your Analytics revenue matches the money you actually took.', 'ebook-store' ), |
| 232 |
'soft', |
| 233 |
__( 'Not counted:', 'ebook-store' ) |
| 234 |
); |
| 235 |
|
| 236 |
ebook_store_advanced_close(); |
| 237 |
|
| 238 |
ebook_store_section_close(); |
| 239 |
|
| 240 |
ebook_store_section_open( |
| 241 |
array( |
| 242 |
'eyebrow' => __( 'Good to know', 'ebook-store' ), |
| 243 |
'title' => __( 'Before you trust the reports', 'ebook-store' ), |
| 244 |
'intro' => __( 'A few things outside this tab decide whether your Google Analytics numbers are complete.', 'ebook-store' ), |
| 245 |
'id' => 'ebook-ga4-notes', |
| 246 |
) |
| 247 |
); |
| 248 |
?> |
| 249 |
|
| 250 |
<ul class="ebook-settings-status-list"> |
| 251 |
<?php |
| 252 |
ebook_store_status_row( |
| 253 |
__( 'Cookie consent', 'ebook-store' ), |
| 254 |
'warn', |
| 255 |
__( 'Ebook Store does not ask visitors for tracking consent. If your country requires it, use a consent plugin and check what your legal duties are before switching this on.', 'ebook-store' ) |
| 256 |
); |
| 257 |
|
| 258 |
ebook_store_status_row( |
| 259 |
__( 'Another Analytics plugin', 'ebook-store' ), |
| 260 |
'warn', |
| 261 |
__( 'If a separate Google Analytics or Site Kit plugin already loads the same measurement ID, you may see page views counted twice. Ebook Store only adds its own ebook events, it does not send a general page view.', 'ebook-store' ) |
| 262 |
); |
| 263 |
|
| 264 |
ebook_store_status_row( |
| 265 |
__( 'New numbers take a while', 'ebook-store' ), |
| 266 |
'muted', |
| 267 |
__( 'Use the Realtime report in Google Analytics to confirm the setup works. Standard reports can take up to 24 hours to catch up, so an empty report today does not mean the settings are wrong.', 'ebook-store' ) |
| 268 |
); |
| 269 |
|
| 270 |
ebook_store_status_row( |
| 271 |
__( 'Payment methods covered', 'ebook-store' ), |
| 272 |
'ok', |
| 273 |
__( 'Purchases and refunds are reported for orders taken through PayPal, Stripe, Adyen and WooCommerce.', 'ebook-store' ), |
| 274 |
array( |
| 275 |
'label' => __( 'Review payment settings', 'ebook-store' ), |
| 276 |
'url' => ebook_store_get_settings_tab_url( 'PayPal' ), |
| 277 |
) |
| 278 |
); |
| 279 |
?> |
| 280 |
</ul> |
| 281 |
|
| 282 |
<?php |
| 283 |
ebook_store_section_close(); |
| 284 |
|