-
-
Notifications
You must be signed in to change notification settings - Fork 67
Add SSO support and magic link handling in get_manage_url #274
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
# Fix: "Manage" Button SSO and Magic Link Support ## Problem The "Manage" button in the "My Sites" widget was not properly redirecting to the admin panel when SSO (Single Sign-On) was enabled. Additionally, when magic links were used for custom domains, the magic link URL was generated on the home URL instead of the admin URL, causing users to be redirected to the front-end page instead of the admin panel after login. ### Issues Identified: 1. **Missing SSO Support**: The "Manage" button did not include SSO parameters, preventing automatic login when clicking the button. 2. **Magic Link Path Issue**: When `wu_get_admin_url()` generated a magic link for custom domains, it created URLs like: ``` https://site.online/?wu_magic_token=... ``` Instead of: ``` https://site.online/wp-admin/?wu_magic_token=... ``` This caused users to be logged in but redirected to the home page instead of the admin panel. 3. **Incompatibility with WP Hide**: The solution needed to respect custom admin paths set by plugins like WP Hide. ## Solution Modified the `get_manage_url()` method in `class-my-sites-element.php` to: 1. **Use `wu_get_admin_url()`** to automatically handle magic link generation when needed for custom domains. 2. **Detect Magic Links**: Check if the generated URL contains `wu_magic_token` parameter. 3. **Fix Magic Link Path**: When a magic link is detected: - Parse the magic link URL to extract the base URL and query string - Get the admin path using `get_admin_url()` (respects WP Hide and other plugins) - Reconstruct the URL with the admin path: `https://site.com/wp-admin/?wu_magic_token=...` 4. **Add SSO Support**: When magic link is not used: - Use `wp_login_url()` with `redirect_to` parameter pointing to the admin URL - Add SSO parameter (`sso=login`) to the login URL - This ensures automatic SSO login flow 5. **Backward Compatibility**: Apply the `wp_ultimo_manage_url` filter for compatibility with older versions and custom implementations. ## Implementation Details ### For `wp_admin` Type: - Uses `wu_get_admin_url()` to get admin URL with automatic magic link support - If magic link exists: Adds admin path directly to the URL - If magic link doesn't exist: Uses `wp_login_url()` with SSO parameter - Applies `wp_ultimo_manage_url` filter ### For `default` Type (Frontend Context): - Same logic as `wp_admin` type when not in admin context - Ensures "Manage" button goes directly to admin, not to front-end URL ### For `custom_page` Type: - No changes (unchanged behavior) ## Technical Notes - **Magic Link Detection**: Uses `strpos()` to check for `wu_magic_token` in the URL - **Admin Path Resolution**: Uses `parse_url(get_admin_url(), PHP_URL_PATH)` to get the admin path, which respects WordPress filters and plugins like WP Hide - **Site Context Switching**: Uses `switch_to_blog()` and `restore_current_blog()` to get correct URLs for the target site - **Fallback**: Defaults to `/wp-admin` if admin path cannot be determined ## Testing Tested scenarios: - ✅ SSO login with standard domains - ✅ Magic link login with custom domains - ✅ Compatibility with WP Hide plugin (custom admin paths) - ✅ Backward compatibility with `wp_ultimo_manage_url` filter - ✅ Both `wp_admin` and `default` types ## Files Modified - `/inc/ui/class-my-sites-element.php` - Modified `get_manage_url()` method ## Related Functions - `wu_get_admin_url()` - Generates admin URLs with magic link support - `wp_login_url()` - WordPress function to get login URL with redirect - `get_admin_url()` - WordPress function to get admin URL (respects filters) - `\WP_Ultimo\SSO\SSO::with_sso()` - Adds SSO parameters to URLs ## Example URLs Generated **With Magic Link:** ``` https://site.online/wp-admin/?wu_magic_token=cacf33253e6a4a3f8f82f4d7944f09757ec5e4953dd5ea095a2bb2dacfe8ec84 ``` **With SSO (no magic link):** ``` https://site.online/wp-login.php?redirect_to=https://site.online/wp-admin&sso=login ``` ## Compatibility - ✅ WordPress Multisite - ✅ WP Hide plugin (custom admin paths) - ✅ Custom domains with magic links - ✅ Standard domains with SSO - ✅ Backward compatible with existing filters
WalkthroughThe Changes
Sequence DiagramsequenceDiagram
participant Client
participant get_manage_url
participant wu_get_admin_url
participant SSO as SSO Handler
participant Filter as wp_ultimo_manage_url
Client->>get_manage_url: Request manage URL
get_manage_url->>wu_get_admin_url: Get admin URL
alt Magic link detected
get_manage_url->>get_manage_url: Reconstruct admin URL<br/>with query params
else No magic link & SSO enabled
get_manage_url->>SSO: Redirect through SSO login
SSO->>get_manage_url: Return SSO redirect URL
else No magic link & SSO disabled
get_manage_url->>get_manage_url: Use standard admin URL
end
get_manage_url->>Filter: Apply wp_ultimo_manage_url filter
Filter->>Client: Return final URL
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Tip 📝 Customizable high-level summaries are now available in beta!You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.
Example instruction:
Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (4)
inc/ui/class-my-sites-element.php (4)
396-412: Clarify and date the “custom modification” header.The docblock and inline “CUSTOM MODIFICATION” comments are clear, but the
@modified_dateis left as2025-01-XX. Please update this to a concrete date and confirm this header style matches the project’s conventions, or simplify it if not needed.
414-459: Harden magic-link/SSO URL handling and reduce duplication.The
wp_adminand default (! is_admin()) branches share almost identical magic-link and SSO logic; keeping two copies risks future drift. Also, the URL handling can be made more robust:
- For magic links, you assume
wp_parse_url($admin_url)(and laterparse_url(get_admin_url(), PHP_URL_PATH)) always returns an array withschemeandhost. A filtered or malformed URL could make thisfalseor omit keys, leading to PHP notices/fatal errors.- You’re manually reconstructing SSO URLs using
$sso->get_url_path()andadd_query_arg. The\WP_Ultimo\SSO\SSO::with_sso($url)helper already encapsulates this behavior and theis_enabled()check.Consider extracting a small private helper on this class (or reusing existing helpers) to encapsulate:
private function build_manage_admin_url( int $site_id ): string { $admin_url = wu_get_admin_url( $site_id ); // Magic-link handling... // SSO handling using \WP_Ultimo\SSO\SSO::with_sso( $login_url ) if available... // wp_ultimo_manage_url filter... }Then call it from both branches. Also, when parsing URLs:
- Prefer
wp_parse_url()everywhere instead ofparse_url()for consistency with WordPress.- Guard against
falseor missing keys before indexing.Example adjustment for the admin-path extraction:
- switch_to_blog($site_id); - $admin_path = parse_url(get_admin_url(), PHP_URL_PATH); - restore_current_blog(); + switch_to_blog($site_id); + $admin_url_for_path = get_admin_url(); + restore_current_blog(); + + $admin_path = wp_parse_url($admin_url_for_path, PHP_URL_PATH) ?: ''; + if ($admin_path === '') { + $admin_path = '/wp-admin'; + }This keeps behavior consistent while making the code safer and easier to maintain.
Also applies to: 485-533
485-545: Confirm intentional behavior change for default (“Same Page”) manage type.For the default type, when
! is_admin(), you now always send users directly to the site’s admin URL (with magic-link/SSO support) and bypass the previous\WP_Ultimo\Current::get_manage_url()behavior. Given the field label ('default' => 'Same Page') this is a semantic change:
- Front-end uses of the My Sites element that relied on “Same Page” navigation (with a site hash in the URL) will now jump straight to admin.
- In admin context (
is_admin()), you still delegate toCurrent::get_manage_url, preserving the old behavior there.If this is the intended new contract, consider:
- Updating the field label/description to match the new behavior, or
- Documenting this as a breaking/behavioral change in the changelog/upgrade notes.
If not intended, you may want to keep the old “Same Page” behavior for default type and introduce the new SSO/magic-link logic only for
'wp_admin'.
396-549: Address coding-standards warnings (trailing whitespace, alignment,parse_url).Static analysis is flagging:
- Trailing whitespace on several lines in this block.
- Misaligned
=signs in some assignments.- Use of
parse_url()instead ofwp_parse_url()for the admin-path extraction.These aren’t runtime bugs but will likely keep code-quality checks red. Cleaning them up (and switching fully to
wp_parse_url()) should make CI happy and keep the file consistent with the rest of the project.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
inc/ui/class-my-sites-element.php(3 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
inc/ui/class-my-sites-element.php (4)
inc/functions/url.php (1)
wu_get_admin_url(107-129)inc/sso/class-sso.php (3)
SSO(39-1113)is_enabled(92-111)get_url_path(1076-1087)inc/functions/site.php (1)
wu_get_site(37-40)inc/class-current.php (1)
Current(20-427)
🪛 GitHub Check: Code Quality Checks
inc/ui/class-my-sites-element.php
[failure] 466-466:
Whitespace found at end of line
[failure] 460-460:
Whitespace found at end of line
[failure] 455-455:
Whitespace found at end of line
[warning] 453-453:
Equals sign not aligned with surrounding assignments; expected 8 spaces but found 1 space
[warning] 451-451:
Equals sign not aligned with surrounding assignments; expected 9 spaces but found 1 space
[warning] 443-443:
Equals sign not aligned with surrounding assignments; expected 4 spaces but found 1 space
[failure] 440-440:
Whitespace found at end of line
[failure] 435-435:
Whitespace found at end of line
[warning] 433-433:
parse_url() is discouraged because of inconsistency in the output across PHP versions; use wp_parse_url() instead.
[failure] 430-430:
Whitespace found at end of line
[warning] 426-426:
Equals sign not aligned with surrounding assignments; expected 3 spaces but found 1 space
[failure] 421-421:
Whitespace found at end of line
[failure] 417-417:
Whitespace found at end of line
[warning] 525-525:
Equals sign not aligned with surrounding assignments; expected 9 spaces but found 1 space
[warning] 517-517:
Equals sign not aligned with surrounding assignments; expected 4 spaces but found 1 space
[warning] 507-507:
parse_url() is discouraged because of inconsistency in the output across PHP versions; use wp_parse_url() instead.
[warning] 500-500:
Equals sign not aligned with surrounding assignments; expected 3 spaces but found 1 space
[failure] 495-495:
Whitespace found at end of line
[failure] 491-491:
Whitespace found at end of line
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: PHP 8.4
- GitHub Check: cypress (8.2, chrome)
- GitHub Check: cypress (8.1, chrome)
| $parsed_url = wp_parse_url($admin_url); | ||
| $base_url = $parsed_url['scheme'] . '://' . $parsed_url['host']; | ||
| if (isset($parsed_url['port'])) { | ||
| $base_url .= ':' . $parsed_url['port']; | ||
| } | ||
|
|
||
| // Get admin path (respects WP Hide and other plugins) | ||
| switch_to_blog($site_id); | ||
| $admin_path = parse_url(get_admin_url(), PHP_URL_PATH); | ||
| restore_current_blog(); | ||
|
|
||
| // Ensure admin path exists, default to /wp-admin if not found | ||
| if (empty($admin_path)) { | ||
| $admin_path = '/wp-admin'; | ||
| } | ||
|
|
||
| // Build new URL with admin path | ||
| $query_string = isset($parsed_url['query']) ? '?' . $parsed_url['query'] : ''; | ||
| $admin_url = $base_url . $admin_path . $query_string; | ||
| } elseif (class_exists('\WP_Ultimo\SSO\SSO')) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Align with WordPress URL helpers and guard against parsing failures.
Both magic-link branches construct $base_url and $admin_path using wp_parse_url() and parse_url() without error checking. To better align with WordPress practices and avoid subtle PHP-version differences:
- Replace
parse_url(get_admin_url(), PHP_URL_PATH)withwp_parse_url(get_admin_url(), PHP_URL_PATH). - Add simple guards when working with
$parsed_urlto avoid notices if parsing fails or components are missing.
For example:
- $parsed_url = wp_parse_url($admin_url);
- $base_url = $parsed_url['scheme'] . '://' . $parsed_url['host'];
+ $parsed_url = wp_parse_url($admin_url);
+ if (! is_array($parsed_url) || empty($parsed_url['scheme']) || empty($parsed_url['host'])) {
+ return $admin_url; // Fallback safely if URL is unexpected.
+ }
+ $base_url = $parsed_url['scheme'] . '://' . $parsed_url['host'];This keeps behavior the same in normal cases but fails safely if filters or environment quirks ever produce non-standard URLs.
Also applies to: 498-517
I'll verify the review comment by examining the actual code and validating the suggestions against WordPress practices.
🏁 Script executed:
#!/bin/bash
# Locate and examine the file at the specified lines
if [ -f "inc/ui/class-my-sites-element.php" ]; then
echo "=== Lines 425-444 ==="
sed -n '425,444p' "inc/ui/class-my-sites-element.php"
echo ""
echo "=== Lines 498-517 ==="
sed -n '498,517p' "inc/ui/class-my-sites-element.php"
else
echo "File not found at expected path"
# Try to find it
find . -name "class-my-sites-element.php" 2>/dev/null | head -5
fiLength of output: 1567
🏁 Script executed:
#!/bin/bash
# Search for wp_parse_url usage patterns in the codebase to understand conventions
echo "=== wp_parse_url usage in codebase ==="
rg -n "wp_parse_url" -A 3 -B 1 --type php | head -40Length of output: 2849
🏁 Script executed:
#!/bin/bash
# Search for parse_url usage to see if it's mixed with wp_parse_url
echo "=== parse_url usage patterns ==="
rg -n "parse_url\(" inc/ui/class-my-sites-element.php -A 2 -B 1 --type phpLength of output: 769
🏁 Script executed:
#!/bin/bash
# Check WordPress source or documentation within repo for wp_parse_url definition
echo "=== Searching for wp_parse_url definition ==="
rg -n "function wp_parse_url" --type php -A 5Length of output: 45
🌐 Web query:
WordPress wp_parse_url function PHP_URL_PATH constant support
💡 Result:
Yes — wp_parse_url accepts PHP's component constants (including PHP_URL_PATH) and will return the path when you pass PHP_URL_PATH. The function is a wrapper around parse_url() and maps PHP_URL_PATH to the 'path' key (introduced in WP 4.7). [1][2]
Sources:
- wp_parse_url() docs. [1]
- Internal mapping of PHP_URL_* constants to keys (includes PHP_URL_PATH). [2]
Replace parse_url() with wp_parse_url() and add guards for missing URL components.
Both locations (lines 433, 507) use parse_url() instead of wp_parse_url(), which is inconsistent with the preceding call on the same URL. Additionally, the code accesses $parsed_url['scheme'] and $parsed_url['host'] without checking if parsing succeeded, risking notices if the URL is malformed or filters produce unexpected results.
Replace parse_url(get_admin_url(), PHP_URL_PATH) with wp_parse_url(get_admin_url(), PHP_URL_PATH) at lines 433 and 507, and add guards immediately after the first wp_parse_url() call:
$parsed_url = wp_parse_url($admin_url);
if (! is_array($parsed_url) || empty($parsed_url['scheme']) || empty($parsed_url['host'])) {
return $admin_url; // Fallback safely if URL is unexpected.
}🧰 Tools
🪛 GitHub Check: Code Quality Checks
[warning] 443-443:
Equals sign not aligned with surrounding assignments; expected 4 spaces but found 1 space
[failure] 440-440:
Whitespace found at end of line
[failure] 435-435:
Whitespace found at end of line
[warning] 433-433:
parse_url() is discouraged because of inconsistency in the output across PHP versions; use wp_parse_url() instead.
[failure] 430-430:
Whitespace found at end of line
[warning] 426-426:
Equals sign not aligned with surrounding assignments; expected 3 spaces but found 1 space
🤖 Prompt for AI Agents
In inc/ui/class-my-sites-element.php around lines 425 to 444 (and also update
the other occurrence at ~507), replace the raw PHP parse_url() calls with
wp_parse_url() and add a guard after the first wp_parse_url($admin_url) call to
ensure parsing succeeded and required components exist; if wp_parse_url doesn't
return an array or the scheme/host are empty, return the original $admin_url as
a safe fallback. Also update the two other parse_url(get_admin_url(),
PHP_URL_PATH) uses to wp_parse_url(get_admin_url(), PHP_URL_PATH) so all URL
parsing is consistent and protected by the same guard.
Fix: "Manage" Button SSO and Magic Link Support
Problem
The "Manage" button in the "My Sites" widget was not properly redirecting to the admin panel when SSO (Single Sign-On) was enabled. Additionally, when magic links were used for custom domains, the magic link URL was generated on the home URL instead of the admin URL, causing users to be redirected to the front-end page instead of the admin panel after login.
Issues Identified:
Missing SSO Support: The "Manage" button did not include SSO parameters, preventing automatic login when clicking the button.
Magic Link Path Issue: When
wu_get_admin_url()generated a magic link for custom domains, it created URLs like:https://site.online/?wu_magic_token=...Instead of:https://site.online/wp-admin/?wu_magic_token=...This caused users to be logged in but redirected to the home page instead of the admin panel.Incompatibility with WP Hide: The solution needed to respect custom admin paths set by plugins like WP Hide.
Solution
Modified the
get_manage_url()method inclass-my-sites-element.phpto:Use
wu_get_admin_url()to automatically handle magic link generation when needed for custom domains.Detect Magic Links: Check if the generated URL contains
wu_magic_tokenparameter.Fix Magic Link Path: When a magic link is detected:
get_admin_url()(respects WP Hide and other plugins)https://site.com/wp-admin/?wu_magic_token=...Add SSO Support: When magic link is not used:
wp_login_url()withredirect_toparameter pointing to the admin URLsso=login) to the login URLBackward Compatibility: Apply the
wp_ultimo_manage_urlfilter for compatibility with older versions and custom implementations.Implementation Details
For
wp_adminType:wu_get_admin_url()to get admin URL with automatic magic link supportwp_login_url()with SSO parameterwp_ultimo_manage_urlfilterFor
defaultType (Frontend Context):wp_admintype when not in admin contextFor
custom_pageType:Technical Notes
strpos()to check forwu_magic_tokenin the URLparse_url(get_admin_url(), PHP_URL_PATH)to get the admin path, which respects WordPress filters and plugins like WP Hideswitch_to_blog()andrestore_current_blog()to get correct URLs for the target site/wp-adminif admin path cannot be determinedTesting
Tested scenarios:
wp_ultimo_manage_urlfilterwp_adminanddefaulttypesFiles Modified
/inc/ui/class-my-sites-element.php- Modifiedget_manage_url()methodRelated Functions
wu_get_admin_url()- Generates admin URLs with magic link supportwp_login_url()- WordPress function to get login URL with redirectget_admin_url()- WordPress function to get admin URL (respects filters)\WP_Ultimo\SSO\SSO::with_sso()- Adds SSO parameters to URLsExample URLs Generated
With Magic Link:
With SSO (no magic link):
Compatibility
Summary by CodeRabbit
Release Notes
Bug Fixes
✏️ Tip: You can customize this high-level summary in your review settings.