MissVeronica / um-directory-private-fields

Extension to Ultimate Member for User setting of private fields in Members Directory.
GNU General Public License v3.0
0 stars 0 forks source link

Fatal PHP Error After Deleting Fields #1

Open tbdeaton opened 1 month ago

tbdeaton commented 1 month ago

Hi! I've been trying to get this plugin to work for a client - I documented some of the issues I'm facing with the plugin functionality on the support forums. One perplexing issue I was seeing was that the plugin was still giving options to hide the two checkboxes (for hiding the fields using the script in the thread referenced above) I removed from the profile form. I finally remembered that removing fields from the form doesn't delete them, so I went back to form and saw them in the Custom Fields section of Add Field. When I deleted them and Updated the form and reloaded the Directory Private Fields section of My Account, I got the fatal error detailed below. I don't think those fields were selected in UM->General->Users settings section, but I'm not certain, as I just deleted the plugin and reinstalled. It's working fine now, but I thought you should know that this error can happen. Thanks!

Update: I just looked at the line the error was on and saw that it is using the same "hide_" prefix in the script I tried using initially. I just wanted to add that the fields I deleted did have meta keys of "hide_city" and "hide_companytype", so that may make this a unique case that only happens if someone had fields with meta keys beginning with "hide" or maybe just ones that are identical to the ones the plugin creates.

PHP Fatal Uncaught TypeError: Cannot access offset of type string on string Stack trace:

0 /wp-includes/class-wp-hook.php(326): UM_Directory_Private_Fields->um_account_content_directory_private_fields_tab()

1 /wp-includes/plugin.php(205): WP_Hook->apply_filters()

2 /wp-content/plugins/ultimate-member/includes/core/class-account.php(781): apply_filters()

3 /wp-content/plugins/ultimate-member/includes/core/class-account.php(70): um\core\Account->get_tab_fields()

4 /wp-content/plugins/ultimate-member/includes/core/class-account.php(258): um\core\Account->init_tabs()

5 /wp-includes/shortcodes.php(434): um\core\Account->ultimatemember_account()

6 internal function: do_shortcode_tag()

7 /wp-includes/shortcodes.php(273): preg_replace_callback()

8 /wp-includes/class-wp-hook.php(324): do_shortcode()

9 /wp-includes/plugin.php(205): WP_Hook->apply_filters()

10 /wp-includes/blocks/post-content.php(50): apply_filters()

11 /wp-includes/class-wp-block.php(519): render_block_core_post_content()

12 /wp-includes/class-wp-block.php(499): WP_Block->render()

13 /wp-includes/blocks.php(2061): WP_Block->render()

14 /wp-includes/blocks.php(2113): render_block()

15 /wp-includes/block-template.php(260): do_blocks()

16 /wp-includes/template-canvas.php(12): get_the_block_template_html()

17 /wp-includes/template-loader.php(106): include('...')

18 /wp-blog-header.php(19): require_once('...')

19 /index.php(17): require('...')

20 {main} thrown in /wp-content/plugins/um-directory-private-fields-main/um-directory-private-fields.php on line 153

Plugin: Ultimate Member - Directory Private Fields File: /wp-content/plugins/um-directory-private-fields-main/um-directory-private-fields.php Line: 153

MissVeronica commented 1 month ago

Copy of your post in the UM Support Forum:

Hey @missveronicatv , thank you for the plugin. I installed it and have a question about it: should this hide the field from user profiles as well? I’m not sure if it’s not working or if I have some settings wrong. With one test Subscriber, I went to the account page and selected the options to hide a number of fields. With another test Subscriber, I’m still able to do two things I don’t want to happen: – See all the fields that should be hidden (do I need to change some setting of the field itself in the form?) – Search for a specific term in a field that should be hidden and have the profile display in directory results (e.g. search for “Birmingham” and the profile which has that as its City still shows up).

Should the plugin allow me to accomplish the privacy options above? Here are my current settings

Thanks so much!

MissVeronica commented 1 month ago

First about your issue "Fatal PHP Error After Deleting Fields"

I will make an update which will avoid the Fatal PHP error and the duplicate issue.

The duplicate issue with custom metakeys having also the hide_ prefix will be solved by excluding them as suspected metakeys from selections as private fields and will be listed as suspects in the description field.

should this hide the field from user profiles as well?

No, the plugin "UM Directory Private Fields" is only making fields in the Members Directory private. I will try to add this feature to the plugin.

Search for a specific term

I will try to add this feature to the plugin.

I will post here when there is an update ready for download.

tbdeaton commented 1 month ago

Thanks so much, @MissVeronica ! By when do you think you may be able to add those features? I'm trying to finish up the project I need these features for in the next week or so. If you think it'll take you longer than that, I can go ahead and see if I can get those features working and share my code here if I'm successful.

MissVeronica commented 1 month ago

Remains some more coding for "Search for a specific term" and more testing for all the features in the new version.

MissVeronica commented 4 weeks ago

Version 2.0.0 is ready for download now.

tbdeaton commented 3 weeks ago

Version 2.0.0 is ready for download now.

That's great! I just tested it. Profile hiding is working well! Ideally, eventually, it wouldn't hide the fields from one's own profile, but that's not really that important - everything is still properly visible when editing the profile...so maybe it's actually better, as it gives the user a chance to see what others will see.

My only other request would be not allowing those fields to be searched for - it's still allowing that, e.g. when I search for "Birmingham" or "Copywriter", the user still shows up in the directory even though City and Job Title are hidden from the profile. Let me know if you think you may be able to do that in the next couple of weeks, otherwise I can see if I can help. I'm not sure if that feature is much more challenging to achieve or not.

Thank you so much! You rock!

MissVeronica commented 3 weeks ago

Thanks for your feedback.

The current plugin version is protecting fields only for the filters in Members Directory. I made a comment in the readme file for the plugin about UM Search Maybe I should add that you can make protected fields searches via filters with the protected fields excluded by UM search.

Members Directory Search

Exclude your private Search fields by the UM Settings in Members Directory
https://docs.ultimatemember.com/article/1513-member-directories-2-1-0#search
tbdeaton commented 2 days ago

Hey @MissVeronica,

I've been working on getting the search to exclude data found in the fields selected to be private by the members. I have to it mostly working, but I've been unable to get the grid to properly clear and display the "We are sorry. We cannot find any users who match your search criteria." message. For example, if I search "Actor", which is the Profession of two members who haven't hidden those fields, the two members show up in the grid. If I then search "Birmingham", which is the City of a member who hid that field, the grid keeps showing the two members from the "Actor" search. If I search "Birmingham" after page load/before any other searches, the grid properly doesn't show anything.

I'm now trying to resolve the issue via JS/JQuery, but no luck so far. Any ideas? Feel free to add any of this code to the plugin if you'd like to extend the functionality. exclude_hidden_users_from_results is the only function that executes.


//The function below doesn't execute - maybe it's an old hook?

add_filter('um_prepare_total_users_query', 'exclude_hidden_users_from_total_count', 10, 2); 

function exclude_hidden_users_from_total_count($query, $args) {
    global $wpdb;

    // Modify the query to exclude users with hidden fields marked as 'yes'
    $query = str_replace(
        'WHERE 1=1',
        "LEFT JOIN {$wpdb->usermeta} um_meta ON (u.ID = um_meta.user_id AND um_meta.meta_key LIKE 'hide_%')
        WHERE (
            (um_meta.meta_key IS NULL OR um_meta.meta_value IS NULL OR um_meta.meta_value NOT LIKE '%yes%')
        )",
        $query
    );

    return $query;
}

// This function below seems to be the only function that actually does anything

add_action('um_ajax_get_members_data', 'exclude_hidden_users_from_results', 10, 3);

function exclude_hidden_users_from_results($data_array, $user_id, $directory_data) {
    global $wpdb;

    // Ensure $data_array is an array
    if (!is_array($data_array)) {
        return $data_array; // If it's not an array, return it as is
    }

    // Fetch hidden fields for the user
    $hidden_fields = $wpdb->get_results($wpdb->prepare("
        SELECT meta_key, meta_value
        FROM {$wpdb->usermeta}
        WHERE user_id = %d AND meta_key LIKE 'hide_%%'
    ", $user_id));

    // Fetch the user's actual metadata
    $user_meta = get_user_meta($user_id);

    // Get the search term
    $search_term = isset($_POST['search']) ? sanitize_text_field($_POST['search']) : '';

    // If no search term, return the array as is
    if (empty($search_term)) {
        return $data_array;
    }

    // Loop through hidden fields and exclude the user if the search term matches a hidden field
    foreach ($hidden_fields as $field) {
        $meta_value = maybe_unserialize($field->meta_value);

        if (is_array($meta_value) && in_array('yes', $meta_value)) {
            $field_name = str_replace('hide_', '', $field->meta_key);

            if (!empty($user_meta[$field_name]) && strpos(strtolower($user_meta[$field_name][0]), strtolower($search_term)) !== false) {
                error_log("Excluding user $user_id because of hidden field: {$field_name}");

                // Return an empty array, signaling no data should be sent for this user
                return [];
            }
        }
    }

    return $data_array;
}

//The function below doesn't execute - maybe it's an old hook?

add_filter('um_members_directory_total_users_query', 'adjust_total_member_count_for_hidden_users', 10, 2);

function adjust_total_member_count_for_hidden_users($query, $args) {
    global $wpdb;

    // Modify the total user count query to exclude users with hidden fields
    $query = str_replace(
        'WHERE 1=1',
        "LEFT JOIN {$wpdb->usermeta} um_meta ON (um_meta.user_id = {$wpdb->users}.ID AND um_meta.meta_key LIKE 'hide_%') 
         WHERE (
            (um_meta.meta_key IS NULL OR um_meta.meta_value IS NULL OR um_meta.meta_value NOT LIKE '%yes%')
        )",
        $query
    );

    return $query;
}

//This function below DOESN'T WORK
add_action('um_ajax_get_members_data', 'hide_empty_grid_if_no_members', 10, 3);

function hide_empty_grid_if_no_members($data_array, $user_id, $directory_data) {
    // If there are no valid users in the data array, show a message instead of the grid
    if (empty($data_array)) {
        echo '<div class="um-members-none"><p>We are sorry. We cannot find any users who match your search criteria.</p></div>';
        return [];
    }
    return $data_array;
} 
MissVeronica commented 1 day ago

You have the the No Users ... message in these locations:

.../plugins/ultimate-member/includes/class-config.php 
183 '_um_directory_no_users' => __( 'We are sorry. We cannot find any users who match your search criteria.', 'ultimate-member' ),
.../plugins/ultimate-member/includes/admin/class-admin.php 
322 '_um_directory_no_users' => array(
.../plugins/ultimate-member/includes/admin/class-site-health.php 
2409 'value' => get_post_meta( $key, '_um_directory_no_users', true ),
.../plugins/ultimate-member/includes/admin/templates/directory/pagination.php
63 'id' => '_um_directory_no_users',
67 'value' => UM()->query()->get_meta_value( '_um_directory_no_users', null, 'na' ), 

In worst case change the message in class-config.php class. I will look at your coding later.