Skip to content

Home app - Support for not requiring login#2883

Open
cairocoder01 wants to merge 4 commits intoDiscipleTools:developfrom
cairocoder01:home-app-not-require-login
Open

Home app - Support for not requiring login#2883
cairocoder01 wants to merge 4 commits intoDiscipleTools:developfrom
cairocoder01:home-app-not-require-login

Conversation

@cairocoder01
Copy link
Collaborator

Currently, the new home app doesn't respect the setting to not require login. It still redirects users through the login. This resolves that an fixes subsequent issues for getting the proper app URLs based on the magic link user instead of the current user.

Some added AI summary from my second commit, which is the bulk of the changes:

Ensures correct user identification when using magic URLs, especially in scenarios where the user is not explicitly logged in.

This change centralizes user ID retrieval using DT_Magic_URL::get_current_user_id to consistently determine the user based on the magic link's post_id and post_type. This prevents issues where the wrong user context was being applied, for example when generating the "Home" link or when determining which apps to display.

It also updates the launcher to pass the user ID to the magic URL generation functions, so that the correct home link is displayed for the user.

This affects the URLs that are used on the main home app screen as well as the app links in the launcher nav and home button. Hopefully there aren't other things I missed, but I'm not entirely sure.

Ensures correct user identification when using magic URLs, especially in scenarios where the user is not explicitly logged in.

This change centralizes user ID retrieval using `DT_Magic_URL::get_current_user_id` to consistently determine the user based on the magic link's `post_id` and `post_type`. This prevents issues where the wrong user context was being applied, for example when generating the "Home" link or when determining which apps to display.

It also updates the launcher to pass the user ID to the magic URL generation functions, so that the correct home link is displayed for the user.
@github-actions
Copy link

github-actions bot commented Feb 6, 2026

PR Review: Home App - Support for Not Requiring Login

Summary

This PR improves magic link handling for the home app when login is not required. The changes centralize user ID retrieval and ensure proper URL generation for non-logged-in users accessing the home app via magic links.


✅ Strengths

  1. Good Centralization: The new DT_Magic_URL::get_current_user_id() and determine_post_id() methods reduce code duplication and provide a single source of truth for user identification from magic link parts.

  2. Proper Variable Passing: The changes correctly pass $user_id through the call chain (launcher templates → helper functions → app methods).

  3. Simplification: The refactoring in class-home-apps.php:726-743 removes a complex nested block and replaces it with a cleaner call to get_link_url_for_post().


🔍 Issues & Concerns

1. Type Safety Issue in get_current_user_id() (dt-reports/magic-url-class.php:429-453)

Line 440: There's a typo in the condition check:

if ( isset( $parts['post_id'], $parts['post_id'] ) ) {

This checks $parts['post_id'] twice instead of checking both $parts['post_id'] and $parts['post_type']. This should be:

if ( isset( $parts['post_id'], $parts['post_type'] ) ) {

Severity: High - This bug could cause incorrect behavior when post_type is missing.


2. Security Concern: Capability Assignment (magic-link-home-app.php:509-512)

if ( !is_user_logged_in() ) {
    DT_ML_Helper::update_user_logged_in_state();
    $current_user = wp_get_current_user();
    $current_user->add_cap( 'access_contacts' ); // give access to get contact id from user id
}

Issues:

  • Adds a capability directly to the user object without persistence
  • The capability is added after update_user_logged_in_state() which may change the current user context
  • No cleanup of this temporary capability
  • Comment suggests this is for "get contact id from user id" but doesn't explain why this specific capability is needed

Recommendation:

  • Add a comment explaining why this capability is required and what check it's satisfying
  • Consider if there's a more targeted way to bypass the specific check without adding a broad capability
  • Verify that this capability doesn't grant unintended access

3. Missing Type Cast (magic-link-home-app.php:505)

Line 505 correctly casts to int:

$user_id = (int) $params['parts']['post_id'];

However, in the original footer_javascript() at line 232, the old code used get_current_user_id() but the new code uses:

'user_id' => DT_Magic_URL::get_current_user_id( $this->parts ),

The get_current_user_id() static method returns an int, but verify that all consumers properly handle the return value.


4. Redundant Code (magic-link-home-app.php:344-365)

The show_launcher_wrapper() method has:

$target_app_url = $this->get_target_app_url();  // Line 344
error_log( 'DT Home: Showing launcher wrapper for URL: ' . $target_app_url );  // Line 345

// ... code ...

$apps = $apps_manager->get_apps_for_user( $user_id );  // Line 361

// Include wrapper template
$wrapper_path = get_template_directory() . '/dt-apps/dt-home/frontend/partials/launcher-wrapper.php';
if ( file_exists( $wrapper_path ) ) {
    // Template has access to variables declared above
    include $wrapper_path;

The comment "Template has access to variables declared above" is good, but the variables actually used need to be clear. From the diff, the template needs $target_app_url, $apps, and $user_id.

The old code at lines 349-352 and 358 has been removed, which looks correct, but ensure all necessary variables are still available to the template.


5. Inconsistent Parameter Documentation

In dt-home-helpers.php:17-22, the function signature changed:

function dt_home_magic_url( $action = '', $key = '', $user_id = null ) {

But in launcher-bottom-nav.php:9, the new docblock comment says:

* @var int $user_id The current user ID based on the magic link key

This is accurate, but the function parameter is actually $user_id = null with a fallback. The documentation could be clearer about when $user_id might be null vs. when it's explicitly passed.


6. Missing Error Handling

In magic-link-home-app.php:361:

$user_id = DT_Magic_URL::get_current_user_id( $parts );

If this returns 0 (no user found), get_apps_for_user(0) is called. What happens in that case? Does the method handle $user_id = 0 gracefully? Consider adding validation.


7. Deleted Code Review (magic-url-base.php:49-66)

The removed code block handled post_id determination, which is now moved to determine_post_id(). This is good refactoring, but:

  • Line 51 in magic-url-base.php now calls $this->magic->determine_post_id( $this->parts ) which modifies $this->parts by reference
  • The old code explicitly set $this->parts['post_id'] after validation
  • Ensure the new method properly sets the post_id in the parts array by reference

🧪 Testing Recommendations

  1. Test with login not required:

    • Verify magic links work when homescreen_require_login() returns false
    • Verify the home app correctly identifies the user from magic link parts
    • Verify apps are filtered correctly for the magic link user (not the logged-in user)
  2. Test with login required:

    • Verify existing behavior is preserved
    • Verify redirection still works correctly
  3. Test edge cases:

    • No user associated with magic link
    • Invalid magic link key
    • Contact without associated user
    • User without contact
  4. Security testing:

    • Verify the temporary access_contacts capability doesn't grant unintended access
    • Test that users can only access their own apps/data

📝 Code Style Notes

  • Line 232: New code uses DT_Magic_URL::get_current_user_id( $this->parts ) - good use of the centralized method
  • Line 233: New require_login parameter added to jsObject - good for JavaScript-side validation
  • Overall: Code follows WordPress coding standards

🔒 Security Assessment

Overall: Low risk with caveats

  • Magic link validation appears correct
  • User ID retrieval is centralized and consistent
  • Concern: The capability addition in the REST endpoint needs careful review
  • Recommendation: Add test coverage for permission checks with and without login

📊 Performance Considerations

  • No obvious performance issues
  • The refactoring reduces complexity and database queries
  • get_link_url_for_post() may create magic keys on-demand (line 490-491) - this is acceptable

✏️ Recommended Changes

Critical:

  1. Fix the typo in get_current_user_id() line 440 ($parts['post_id'], $parts['post_id']$parts['post_id'], $parts['post_type'])

High Priority:
2. Add documentation explaining why access_contacts capability is needed in the REST endpoint
3. Add validation for $user_id = 0 cases

Nice to Have:
4. Add PHPDoc return type for get_current_user_id() to clarify it returns int
5. Consider adding unit tests for the new determine_post_id() and get_current_user_id() methods


✅ Approval Status

Approved with minor changes recommended

The core logic is sound and the refactoring improves code organization. The critical bug (duplicate post_id check) should be fixed before merge, but the rest are minor improvements.

Great work on this refactoring! The centralization of user ID logic will make the codebase easier to maintain. 🎉


Reviewed by Claude Code

@github-actions
Copy link

github-actions bot commented Feb 6, 2026

Code Review - PR #2883

Summary

This PR addresses an important issue where the home app was not respecting the "require login" setting and was redirecting users through login even when not required. The changes centralize user ID retrieval through magic links and ensure proper user context throughout the home app.

Positive Aspects ✅

  1. Good architectural improvement: Centralizing user ID determination via DT_Magic_URL::get_current_user_id() is a solid pattern that reduces code duplication and improves consistency.

  2. Refactoring in magic-url-base.php: Extracting the post ID determination logic into determine_post_id() method is a nice cleanup that improves code organization (lines 46-53).

  3. Simplified logic in class-home-apps.php: The replacement of the complex template-specific logic (lines 731-760 in old code) with a simpler call to get_link_url_for_post() is much cleaner and more maintainable.

  4. Proper parameter threading: The changes correctly thread the $user_id parameter through the call chain from partials to helper functions.

Issues Found 🚨

1. Critical: Undefined Method Call (dt-apps/dt-home/magic-link-home-app.php:509)

if ( !is_user_logged_in() ) {
    DT_ML_Helper::update_user_logged_in_state();
}

Problem: The class DT_ML_Helper and method update_user_logged_in_state() do not exist in the codebase. This will cause a fatal error when the condition is met.

Recommendation: Either remove this code block if it's not needed, or ensure the class/method exists. If this is from another branch/PR, that dependency should be noted.

2. Type Safety Issue (dt-apps/dt-home/magic-link-home-app.php:497)

$user_id = (int) $params['parts']['post_id'];

Problem: While you cast to int here, the value in $params['parts']['post_id'] may not be set if the magic link is invalid or malformed, which could result in $user_id = 0.

Recommendation: Add validation:

$user_id = isset($params['parts']['post_id']) ? (int) $params['parts']['post_id'] : 0;
if ( $user_id === 0 ) {
    return new WP_Error( __METHOD__, 'Invalid user ID', [ 'status' => 400 ] );
}

3. Missing Null Check (dt-apps/dt-home/includes/class-home-apps.php:734)

$post_id = get_user_option( 'corresponds_to_contact', $user_id );
$url = DT_Magic_URL::get_link_url_for_post(
    $app_meta['post_type'],
    $post_id,  // Could be false/empty
    $app_ml_root,
    $app_ml_type
);

Problem: get_user_option() can return false if the option doesn't exist. Passing a falsy value to get_link_url_for_post() could cause issues.

Recommendation: Add validation:

$post_id = get_user_option( 'corresponds_to_contact', $user_id );
if ( !empty( $post_id ) ) {
    $url = DT_Magic_URL::get_link_url_for_post(
        $app_meta['post_type'],
        $post_id,
        $app_ml_root,
        $app_ml_type
    );
    if ( ! empty( $url ) ) {
        $app['url'] = $url;
    }
}

4. Typo in PHPDoc (dt-reports/magic-url-class.php:477)

/**
 * Get the magic url link for a past  // "past" should be "post"

Code Quality Observations

  1. Missing PHPDoc param types: The new get_current_user_id() method (magic-url-class.php:437) has basic PHPDoc but could benefit from more explicit type hints:

    /**
     * Get the current user ID from the magic link parts or the currently logged-in user
     * @param array $parts Link parts with post_id and post_type set
     * @return int The user ID, or 0 if not found
     */
  2. Inconsistent array access: Consider using null coalescing operator for cleaner code:

    $user_id = $user_id ?? get_current_user_id();  // Already done ✓
    $post_id = $parts['post_id'] ?? null;

Security Considerations

  1. Input sanitization: The code properly uses dt_recursive_sanitize_array() on REST endpoint parameters ✅
  2. User capability checks: Ensure that magic link keys can't be used to access unauthorized user contexts (appears to be handled by existing magic link system) ✅
  3. Type casting: Good use of (int) casting for user IDs ✅

Testing Recommendations

  1. Test with require_login setting disabled (the main use case)
  2. Test with invalid/expired magic link keys
  3. Test with users who don't have a corresponding contact
  4. Test the launcher wrapper with various app types
  5. Test the JavaScript fallback when jsObject.user_id === 0 and jsObject.require_login === false

Performance

No significant performance concerns. The changes actually reduce database queries by using the existing get_link_url_for_post() helper instead of multiple metadata lookups.

Suggested Action Items

  1. MUST FIX: Remove or implement DT_ML_Helper::update_user_logged_in_state() call
  2. SHOULD FIX: Add validation for $user_id and $post_id values before use
  3. NICE TO HAVE: Fix PHPDoc typo
  4. NICE TO HAVE: Add additional test coverage for the no-login-required scenario

Overall, this is a good improvement that simplifies the code and fixes an important bug. The main blocker is the undefined method call that needs to be addressed before merging.

@github-actions
Copy link

github-actions bot commented Feb 6, 2026

Pull Request Review - Home App: Support for not requiring login

Summary

This PR addresses an important issue where the home app wasn't respecting the require_login setting, forcing users through login even when it should be optional. The fix centralizes user identification via DT_Magic_URL::get_current_user_id() to ensure the correct user context is applied throughout the magic link flow.


Code Quality & Best Practices ✅

Strengths:

  • Centralization: The introduction of DT_Magic_URL::get_current_user_id() and determine_post_id() are excellent architectural improvements that reduce code duplication
  • Consistent user context: Passing $user_id through the call chain (helpers → partials) maintains proper user context
  • Code simplification: The refactoring in class-home-apps.php:726-743 removes complex template-specific logic in favor of the simpler get_link_url_for_post() method
  • Good parameter defaults: Using null coalescing operator (??) for optional parameters is clean

Minor concerns:

  1. Magic number removal (dt-apps/dt-home/frontend/partials/launcher-wrapper.php:20-23): The removed code was getting apps but wasn't being used. Good cleanup, though the comment about "Get all apps for the apps selector" is still present above despite the code being removed.

Potential Bugs & Issues ⚠️

  1. JavaScript authentication check logic (dt-apps/dt-home/assets/js/home-app.js:10):

    if (jsObject.user_id === 0 && jsObject.require_login) {

    The new condition adds && jsObject.require_login, but the comment above still says "This should not happen as PHP redirects unauthenticated users". This is now intentionally allowed when require_login is false, so the comment is misleading. Recommendation: Update the comment to reflect the new behavior.

  2. Error handling in launcher wrapper (dt-apps/dt-home/magic-link-home-app.php:345-364):

    • The new code parses $_SERVER['REQUEST_URI'] and assumes $url_parts[1] exists
    • Risk: If the URL structure is unexpected (e.g., empty path), this could cause an undefined array offset error
    • Recommendation: Add validation:
    if (isset($url_parts[1]) && !empty($url_parts[1])) {
        $target_magic_url = new DT_Magic_URL($url_parts[1]);
        // ...
    } else {
        // Handle error case
    }
  3. Inconsistent user_id casting (dt-reports/magic-url-class.php:430-452):

    • Line 438 and 444 cast to (int) explicitly, which is good
    • However, the function signature doesn't indicate that $parts['post_id'] should be an int
    • Recommendation: Consider adding type hints or documenting expected types
  4. Missing validation (dt-apps/dt-home/magic-link-home-app.php:502-505):

    $user_id = (int) $params['parts']['post_id'];

    This assumes $params['parts']['post_id'] exists. If it doesn't, this will cast null or undefined to 0.

    • Recommendation: Add existence check before casting

Security Concerns 🔒

  1. Input sanitization (dt-apps/dt-home/magic-link-home-app.php:349):

    $request_uri = isset( $_SERVER['REQUEST_URI'] ) ? esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : '';

    Good use of sanitization functions. ✅

  2. Magic link validation: The new determine_post_id() method properly validates magic links before using them, which maintains security. ✅

  3. User context integrity: The centralized user ID retrieval ensures that apps can't accidentally leak data to the wrong user by using the wrong context. This is a security improvement. ✅

Recommendation: Since the app now supports unauthenticated access (when require_login is false), ensure that any sensitive operations in the home app properly check permissions and don't rely solely on the presence of a user ID.


Performance Considerations 🚀

  1. Database queries: The new code path adds a call to get_user_option() for each app in get_apps_for_frontend(). For users with many apps, this could add up.

    • Current: Lines 727, 735 call get_user_option() or get_post_meta()
    • Impact: Likely minimal since these are typically cached by WordPress, but worth monitoring
  2. Code removed: The PR removes ~65 lines of complex logic, which should slightly improve performance. ✅


Test Coverage 📝

Concerns:

  • No test files were modified in this PR
  • The changes affect critical authentication and user identification logic
  • Recommendation: Add tests covering:
    1. Home app access when require_login is true vs false
    2. Correct user ID resolution from magic links (user post_type vs contacts post_type)
    3. Edge cases like missing or invalid magic link keys
    4. Apps list retrieval for different user contexts

Additional Observations

  1. Breaking changes: The signature change to dt_home_magic_url() adds an optional parameter, maintaining backward compatibility. ✅

  2. Documentation: The new @param annotations are helpful (e.g., in launcher-bottom-nav.php:9). ✅

  3. Code consistency: The refactoring uses existing utility methods (get_link_url_for_post()) rather than duplicating logic. ✅

  4. Missing error log cleanup (dt-apps/dt-home/magic-link-home-app.php:346):

    error_log( 'DT Home: Showing launcher wrapper for URL: ' . $target_app_url );

    This debug log is still present. Should it be removed for production?


Recommendations Summary

High Priority:

  1. Add validation for $url_parts[1] before using it (undefined offset risk)
  2. Validate $params['parts']['post_id'] exists before casting to int

Medium Priority:
3. Update JavaScript comment to reflect the new authentication flow behavior
4. Add test coverage for the new user identification logic
5. Consider removing or conditionalizing the error_log statement

Low Priority:
6. Clean up orphaned comment in launcher-wrapper.php
7. Document expected types for $parts array


Verdict

This is a solid PR that addresses a real bug and improves code architecture through centralization. The core logic changes are sound, but there are a few potential edge cases around array access that should be hardened before merging. Once the high-priority validation issues are addressed, this should be good to merge.

Estimated risk level: Medium (due to authentication flow changes and potential undefined array offsets)


Review conducted using Claude Code following repository conventions in CLAUDE.md

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant