Changeset 3744682
- Timestamp:
- 10/13/2026 06:30:07 PM (3 days ago)
- Location:
- tagsmith
- Files:
-
- 12 edited
- 1 copied
-
tags/2.1.1 (copied) (copied from tagsmith/trunk )
-
tags/2.1.1/package-lock.json (modified) (2 diffs)
-
tags/2.1.1/package.json (modified) (1 diff)
-
tags/2.1.1/readme.txt (modified) (2 diffs)
-
tags/2.1.1/src/Admin/OAuthReturn.php (modified) (2 diffs)
-
tags/2.1.1/src/Auth/OAuthFlow.php (modified) (6 diffs)
-
tags/2.1.1/tagsmith.php (modified) (2 diffs)
-
trunk/package-lock.json (modified) (2 diffs)
-
trunk/package.json (modified) (1 diff)
-
trunk/readme.txt (modified) (2 diffs)
-
trunk/src/Admin/OAuthReturn.php (modified) (2 diffs)
-
trunk/src/Auth/OAuthFlow.php (modified) (6 diffs)
-
trunk/tagsmith.php (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
tagsmith/tags/2.1.1/package-lock.json
r3744485 r3744682 1 1 { 2 2 "name": "tagsmith", 3 "version": "2.1. 0",3 "version": "2.1.1", 4 4 "lockfileVersion": 3, 5 5 "requires": true, … … 7 7 "": { 8 8 "name": "tagsmith", 9 "version": "2.1. 0",9 "version": "2.1.1", 10 10 "devDependencies": { 11 11 "@playwright/test": "^1.63.0", -
tagsmith/tags/2.1.1/package.json
r3744485 r3744682 2 2 "name": "tagsmith", 3 3 "private": true, 4 "version": "2.1. 0",4 "version": "2.1.1", 5 5 "scripts": { 6 6 "build": "wp-scripts build --webpack-src-dir=assets/src", -
tagsmith/tags/2.1.1/readme.txt
r3744485 r3744682 5 5 Tested up to: 7.1 6 6 Requires PHP: 8.1 7 Stable tag: 2.1. 07 Stable tag: 2.1.1 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 146 146 == Changelog == 147 147 148 = 2.1.1 = 149 * Fixed: the Google sign-in return no longer passes through wp-admin, so sites that send logged-out wp-admin requests to a login or account page (membership and LMS plugins) can connect. 150 148 151 = 2.1.0 = 149 152 * New: ad pixels for Meta, Google Ads, TikTok, LinkedIn, Microsoft Advertising, Pinterest, Snap and X, set up in the new Ads & pixels tab and off until you switch one on. -
tagsmith/tags/2.1.1/src/Admin/OAuthReturn.php
r3744428 r3744682 16 16 /** 17 17 * Wires OAuthFlow::receive() and OAuthFlow::finalize() into WordPress. 18 * The relay's return reaches receive() through maybe_receive() (front end); 19 * the admin-post actions remain for the BYO redirect and older in-flight returns. 18 20 * 19 21 * CSRF note: these handlers do not use a nonce. The relay's handoff is a … … 73 75 */ 74 76 public function register(): void { 77 add_action( 'init', array( $this, 'maybe_receive' ), 1 ); 75 78 add_action( 'admin_post_tagsmith_oauth_return', array( $this, 'receive' ) ); 76 79 add_action( 'admin_post_nopriv_tagsmith_oauth_return', array( $this, 'receive' ) ); 77 80 add_action( 'admin_init', array( $this, 'maybe_finalize' ) ); 81 } 82 83 /** 84 * Phase 1 on a front-end URL: takes the relay's POST to 85 * home_url( '/?tagsmith_oauth_return=1' ), which does not pass through 86 * wp-admin (plugins that redirect logged-out wp-admin requests would 87 * swallow an admin-post.php return). Anything but a POST with the marker 88 * is left alone. Same protection as the admin-post path: the single-use 89 * random state checked in receive(). 90 */ 91 public function maybe_receive(): void { 92 $method = isset( $_SERVER['REQUEST_METHOD'] ) && is_string( $_SERVER['REQUEST_METHOD'] ) ? strtoupper( sanitize_text_field( wp_unslash( $_SERVER['REQUEST_METHOD'] ) ) ) : ''; 93 94 if ( 'POST' !== $method ) { 95 return; 96 } 97 98 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- CSRF protection is the single-use random state checked in receive() (see class doc). 99 if ( ! isset( $_GET['tagsmith_oauth_return'] ) || ! is_string( $_GET['tagsmith_oauth_return'] ) ) { 100 return; 101 } 102 103 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- see above. 104 if ( '1' !== sanitize_text_field( wp_unslash( $_GET['tagsmith_oauth_return'] ) ) ) { 105 return; 106 } 107 108 $this->receive(); 78 109 } 79 110 -
tagsmith/tags/2.1.1/src/Auth/OAuthFlow.php
r3744485 r3744682 163 163 164 164 /** 165 * The OAuth return endpoint (also the BYO redirect URI to register). 165 * The BYO redirect URI users register with Google. Google's return here is 166 * a logged-in GET, so wp-admin is fine. The relay does not use this URL: 167 * see relay_return_url(). 166 168 */ 167 169 public static function return_url(): string { … … 170 172 171 173 /** 174 * Where the relay hands the browser back: the WordPress address (not 175 * wp-admin). 176 * 177 * The handoff is a cross-site POST without cookies, so WordPress sees a 178 * logged-out request. Membership, LMS and "hide wp-admin" plugins redirect 179 * logged-out wp-admin requests to a login or account page before this 180 * plugin can run, while this URL reaches OAuthReturn::maybe_receive() on 181 * init. It is built from site_url(), not home_url(): the site address can 182 * be a headless front end or another origin, whereas site_url() is where 183 * WordPress runs and shares its origin and path with admin_url(). The relay 184 * accepts this shape from 2.1.1 on. 185 */ 186 public static function relay_return_url(): string { 187 return add_query_arg( 'tagsmith_oauth_return', '1', site_url( '/' ) ); 188 } 189 190 /** 172 191 * Starts a connection: creates a single-use state bound to the user and 173 192 * returns the URL to send the browser to (the relay, or Google in BYO mode). … … 175 194 * @param int $user_id The user starting the flow. 176 195 * @param string[] $features Subset of ['analytics','searchconsole']. 177 * @throws ApiError 'https_required' when wp-admin is served over plain 178 * http on a non-local host: the relay and Google both 179 * reject a non-https return URL. 196 * @throws ApiError 'https_required' when wp-admin (or, for the relay, the 197 * WordPress address) is served over plain http on a 198 * non-local host: the relay and Google both reject a 199 * non-https return URL. 180 200 */ 181 201 public function start_url( int $user_id, array $features ): string { 182 if ( ! self::secure_return_url() ) { 183 throw new ApiError( 'https_required', 'Google sign-in needs an https admin URL.' ); 202 $byo = $this->usable_byo_credentials(); 203 204 // Google gets return_url(); the relay gets relay_return_url(). Both reject plain http off local hosts. 205 if ( ! self::secure_url( self::return_url() ) || ( null === $byo && ! self::secure_url( self::relay_return_url() ) ) ) { 206 throw new ApiError( 'https_required', 'Google sign-in needs an https admin and WordPress address.' ); 184 207 } 185 208 … … 191 214 ); 192 215 193 $byo = $this->usable_byo_credentials();194 195 216 if ( null === $byo ) { 196 217 set_transient( self::START_PREFIX . $state, $start, 600 ); … … 198 219 $query = array( 199 220 'state' => $state, 200 'return_url' => self::re turn_url(),221 'return_url' => self::relay_return_url(), 201 222 'scopes' => implode( ',', $features ), 202 223 'site' => home_url(), … … 684 705 685 706 /** 686 * Whether theOAuth return URL is acceptable to the relay and Google:707 * Whether an OAuth return URL is acceptable to the relay and Google: 687 708 * https, or plain http only on a local development host. 688 */ 689 private static function secure_return_url(): bool { 690 $url = self::return_url(); 709 * 710 * @param string $url Return URL. 711 */ 712 private static function secure_url( string $url ): bool { 691 713 $scheme = strtolower( (string) wp_parse_url( $url, PHP_URL_SCHEME ) ); 692 714 -
tagsmith/tags/2.1.1/tagsmith.php
r3744485 r3744682 4 4 * Plugin URI: https://shivaatripathi.com/tagsmith/ 5 5 * Description: See Google Analytics 4 reports inside WordPress: a clear dashboard, per-post stats and Search Console. Read-only Google access. No nags. 6 * Version: 2.1. 06 * Version: 2.1.1 7 7 * Requires at least: 6.7 8 8 * Requires PHP: 8.1 … … 19 19 defined( 'ABSPATH' ) || exit; 20 20 21 define( 'TAGSMITH_VERSION', '2.1. 0' );21 define( 'TAGSMITH_VERSION', '2.1.1' ); 22 22 define( 'TAGSMITH_FILE', __FILE__ ); 23 23 define( 'TAGSMITH_DIR', plugin_dir_path( __FILE__ ) ); -
tagsmith/trunk/package-lock.json
r3744485 r3744682 1 1 { 2 2 "name": "tagsmith", 3 "version": "2.1. 0",3 "version": "2.1.1", 4 4 "lockfileVersion": 3, 5 5 "requires": true, … … 7 7 "": { 8 8 "name": "tagsmith", 9 "version": "2.1. 0",9 "version": "2.1.1", 10 10 "devDependencies": { 11 11 "@playwright/test": "^1.63.0", -
tagsmith/trunk/package.json
r3744485 r3744682 2 2 "name": "tagsmith", 3 3 "private": true, 4 "version": "2.1. 0",4 "version": "2.1.1", 5 5 "scripts": { 6 6 "build": "wp-scripts build --webpack-src-dir=assets/src", -
tagsmith/trunk/readme.txt
r3744485 r3744682 5 5 Tested up to: 7.1 6 6 Requires PHP: 8.1 7 Stable tag: 2.1. 07 Stable tag: 2.1.1 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 146 146 == Changelog == 147 147 148 = 2.1.1 = 149 * Fixed: the Google sign-in return no longer passes through wp-admin, so sites that send logged-out wp-admin requests to a login or account page (membership and LMS plugins) can connect. 150 148 151 = 2.1.0 = 149 152 * New: ad pixels for Meta, Google Ads, TikTok, LinkedIn, Microsoft Advertising, Pinterest, Snap and X, set up in the new Ads & pixels tab and off until you switch one on. -
tagsmith/trunk/src/Admin/OAuthReturn.php
r3744428 r3744682 16 16 /** 17 17 * Wires OAuthFlow::receive() and OAuthFlow::finalize() into WordPress. 18 * The relay's return reaches receive() through maybe_receive() (front end); 19 * the admin-post actions remain for the BYO redirect and older in-flight returns. 18 20 * 19 21 * CSRF note: these handlers do not use a nonce. The relay's handoff is a … … 73 75 */ 74 76 public function register(): void { 77 add_action( 'init', array( $this, 'maybe_receive' ), 1 ); 75 78 add_action( 'admin_post_tagsmith_oauth_return', array( $this, 'receive' ) ); 76 79 add_action( 'admin_post_nopriv_tagsmith_oauth_return', array( $this, 'receive' ) ); 77 80 add_action( 'admin_init', array( $this, 'maybe_finalize' ) ); 81 } 82 83 /** 84 * Phase 1 on a front-end URL: takes the relay's POST to 85 * home_url( '/?tagsmith_oauth_return=1' ), which does not pass through 86 * wp-admin (plugins that redirect logged-out wp-admin requests would 87 * swallow an admin-post.php return). Anything but a POST with the marker 88 * is left alone. Same protection as the admin-post path: the single-use 89 * random state checked in receive(). 90 */ 91 public function maybe_receive(): void { 92 $method = isset( $_SERVER['REQUEST_METHOD'] ) && is_string( $_SERVER['REQUEST_METHOD'] ) ? strtoupper( sanitize_text_field( wp_unslash( $_SERVER['REQUEST_METHOD'] ) ) ) : ''; 93 94 if ( 'POST' !== $method ) { 95 return; 96 } 97 98 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- CSRF protection is the single-use random state checked in receive() (see class doc). 99 if ( ! isset( $_GET['tagsmith_oauth_return'] ) || ! is_string( $_GET['tagsmith_oauth_return'] ) ) { 100 return; 101 } 102 103 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- see above. 104 if ( '1' !== sanitize_text_field( wp_unslash( $_GET['tagsmith_oauth_return'] ) ) ) { 105 return; 106 } 107 108 $this->receive(); 78 109 } 79 110 -
tagsmith/trunk/src/Auth/OAuthFlow.php
r3744485 r3744682 163 163 164 164 /** 165 * The OAuth return endpoint (also the BYO redirect URI to register). 165 * The BYO redirect URI users register with Google. Google's return here is 166 * a logged-in GET, so wp-admin is fine. The relay does not use this URL: 167 * see relay_return_url(). 166 168 */ 167 169 public static function return_url(): string { … … 170 172 171 173 /** 174 * Where the relay hands the browser back: the WordPress address (not 175 * wp-admin). 176 * 177 * The handoff is a cross-site POST without cookies, so WordPress sees a 178 * logged-out request. Membership, LMS and "hide wp-admin" plugins redirect 179 * logged-out wp-admin requests to a login or account page before this 180 * plugin can run, while this URL reaches OAuthReturn::maybe_receive() on 181 * init. It is built from site_url(), not home_url(): the site address can 182 * be a headless front end or another origin, whereas site_url() is where 183 * WordPress runs and shares its origin and path with admin_url(). The relay 184 * accepts this shape from 2.1.1 on. 185 */ 186 public static function relay_return_url(): string { 187 return add_query_arg( 'tagsmith_oauth_return', '1', site_url( '/' ) ); 188 } 189 190 /** 172 191 * Starts a connection: creates a single-use state bound to the user and 173 192 * returns the URL to send the browser to (the relay, or Google in BYO mode). … … 175 194 * @param int $user_id The user starting the flow. 176 195 * @param string[] $features Subset of ['analytics','searchconsole']. 177 * @throws ApiError 'https_required' when wp-admin is served over plain 178 * http on a non-local host: the relay and Google both 179 * reject a non-https return URL. 196 * @throws ApiError 'https_required' when wp-admin (or, for the relay, the 197 * WordPress address) is served over plain http on a 198 * non-local host: the relay and Google both reject a 199 * non-https return URL. 180 200 */ 181 201 public function start_url( int $user_id, array $features ): string { 182 if ( ! self::secure_return_url() ) { 183 throw new ApiError( 'https_required', 'Google sign-in needs an https admin URL.' ); 202 $byo = $this->usable_byo_credentials(); 203 204 // Google gets return_url(); the relay gets relay_return_url(). Both reject plain http off local hosts. 205 if ( ! self::secure_url( self::return_url() ) || ( null === $byo && ! self::secure_url( self::relay_return_url() ) ) ) { 206 throw new ApiError( 'https_required', 'Google sign-in needs an https admin and WordPress address.' ); 184 207 } 185 208 … … 191 214 ); 192 215 193 $byo = $this->usable_byo_credentials();194 195 216 if ( null === $byo ) { 196 217 set_transient( self::START_PREFIX . $state, $start, 600 ); … … 198 219 $query = array( 199 220 'state' => $state, 200 'return_url' => self::re turn_url(),221 'return_url' => self::relay_return_url(), 201 222 'scopes' => implode( ',', $features ), 202 223 'site' => home_url(), … … 684 705 685 706 /** 686 * Whether theOAuth return URL is acceptable to the relay and Google:707 * Whether an OAuth return URL is acceptable to the relay and Google: 687 708 * https, or plain http only on a local development host. 688 */ 689 private static function secure_return_url(): bool { 690 $url = self::return_url(); 709 * 710 * @param string $url Return URL. 711 */ 712 private static function secure_url( string $url ): bool { 691 713 $scheme = strtolower( (string) wp_parse_url( $url, PHP_URL_SCHEME ) ); 692 714 -
tagsmith/trunk/tagsmith.php
r3744485 r3744682 4 4 * Plugin URI: https://shivaatripathi.com/tagsmith/ 5 5 * Description: See Google Analytics 4 reports inside WordPress: a clear dashboard, per-post stats and Search Console. Read-only Google access. No nags. 6 * Version: 2.1. 06 * Version: 2.1.1 7 7 * Requires at least: 6.7 8 8 * Requires PHP: 8.1 … … 19 19 defined( 'ABSPATH' ) || exit; 20 20 21 define( 'TAGSMITH_VERSION', '2.1. 0' );21 define( 'TAGSMITH_VERSION', '2.1.1' ); 22 22 define( 'TAGSMITH_FILE', __FILE__ ); 23 23 define( 'TAGSMITH_DIR', plugin_dir_path( __FILE__ ) );
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)