WordPress.org

Ready to get started?Download WordPress

Forums

Simple User Listing
[resolved] About search function (13 posts)

  1. chathuranga
    Member
    Posted 7 months ago #

    Hi,

    At first, thank you very much for your plugin. I'm testing this with a single site and the "post name" permalink. I added this shortcode to a page [userlist role="author" number="5"].

    When page is loaded it is working perfectly. But when I do a search it shows all users relevant to the searched word without considering the user role.

    Let me know is there any possibility to filter search results according to the user role? I mean; when I use [userlist role="author" number="5"] and do a search with typing a name; I need to show only authors as the searched results, [userlist role="company" number="5"] then company users only as the searched results.

    Thanks

    http://wordpress.org/plugins/simple-user-listing/

  2. helgatheviking
    Member
    Plugin Author

    Posted 7 months ago #

    Are you using the most recent version, because I can't reproduce this locally. If so, can you send me some admin credentials so I can take a look?

    http://www.kathyisawesome.com/contact

  3. CK MacLeod
    Member
    Posted 5 months ago #

    Hi - I also don't find arguments used in the shortcode carrying over into the search results, for instance the "exclude" and "orderby" variables. Was actually wondering if it was even the intended functionality or had to be coded into a custom search.

    Am using 1.52. Have tried it both straight "out of the box" and with my customized templates. So, to be absolutely clear:

    [userlist number="50" meta_key="last_name" orderby="meta_value" order="ASC" exclude="5"]

    produces an alphabetical list ordered by last name, author with User-ID #5 excluded, but a user search produces a list of users (authors) apparently in order of search relevance, user ID #5 included.

    Initial efforts to write a modified search at least capturing the exclusion variable have not so far led to any luck.

  4. helgatheviking
    Member
    Plugin Author

    Posted 5 months ago #

    Can you try with a default theme and all other plugins disabled, because I still cannot reproduce this. Basically, is something else filtering pre_user_query and causing a conflict?

    I just tested your shortcode locally (just changing the exclude from 5 to 8), and the query object created by the shortcode during a search shows that the exclude and order parameters are both included and correctly formulated into the query_where string.

    object(WP_User_Query)[131]
      public 'query_vars' => &
        array (size=17)
          'blog_id' => int 1
          'role' => string '' (length=0)
          'meta_key' => string 'last_name' (length=9)
          'meta_value' => string '' (length=0)
          'meta_compare' => string '' (length=0)
          'include' =>
            array (size=0)
              empty
          'exclude' =>
            array (size=1)
              0 => string '8' (length=1)
          'search' => string '*student*' (length=9)
          'search_columns' =>
            array (size=0)
              empty
          'orderby' => string 'meta_value' (length=10)
          'order' => string 'ASC' (length=3)
          'offset' => int 0
          'number' => int 50
          'count_total' => boolean true
          'fields' => string 'all' (length=3)
          'who' => string '' (length=0)
          'query_id' => string 'simple_user_listing' (length=19)
      public 'results' => null
      public 'total_users' => int 0
      public 'query_fields' => string 'SQL_CALC_FOUND_ROWS wp_users.*' (length=30)
      public 'query_from' => string 'FROM wp_users INNER JOIN wp_usermeta ON (wp_users.ID = wp_usermeta.user_id)' (length=75)
      public 'query_where' => string 'WHERE 1=1 AND (user_login LIKE '%student%' OR user_nicename LIKE '%student%') AND (wp_usermeta.meta_key = 'last_name' ) AND wp_users.ID NOT IN (8)' (length=146)
      public 'query_orderby' => string 'ORDER BY wp_usermeta.meta_value ASC' (length=35)
      public 'query_limit' => string 'LIMIT 50' (length=8)

    `

  5. CK MacLeod
    Member
    Posted 5 months ago #

    Thanks for your reply, and for confirming that the shortcode terms are supposed to carry over to the user search. I just started testing, and will report my findings.

    Setting up the plug-in at a different site brought up something that confused me months ago when I first started using this plug-in, which I'd set aside. I don't mean to waste your time, but I think the problem may turn out to be connected, and might even lead to something useful for you and other users of your plug-in

    The SUL search is initially set up to "Search authors by name." So, if we add SUL on a site with an author named "Miller," and we search for "Miller," we'll bring up the author or authors named "Miller," with links to all posts by however many Millers.

    To my understanding, this is how it's supposed to work, and getting the search to search for anything else ought to require creating a custom search function, as in the "billing_city" example you use under your FAQs.

    Interestingly (and usefully!), for reasons unclear to me, and without my having done anything (intentionally), on the site where I first installed the plug-in, if I do a user search for "Miller," it will bring up all of the authors who mention "Miller" in a custom field added via the membership plug-in S2Member and stored in the usermeta table.

    I'll add that I was delighted with this to me unexpected functionality, as I thought it was something I was going to have to figure out how to add later on. I also expect that I will need to understand exactly why it's happening in order to gain control over types of searches and outputs, since eventually I'd like to able to give users a wider range of options for narrowing searches and/or results.

    Here's the page - it's a site in "Beta," but I hope for not much longer - where the initial list DOES employ the shortcode parameters, but a search DOES NOT. On the other hand, it DOES search the usermeta table and a specific field within it without my ever having specifically "asked" for that functionality - you can test using "Miller" or "Ashtanga," for example:

    The YIR - Listings

    You'll see that in my customization I added a note on searching the entirety of the user "profiles" at this site. I'll just need to figure out how and why to get the further control I want, and to avoid bad surprises (i.e., the day that functionality just disappears).

    A suspicion is that there is some unexpected fraternization between your plug-in and S2Member that produces the custom field, but it's just a suspicion at this point, and for various reasons somewhat laborious to test.

  6. helgatheviking
    Member
    Plugin Author

    Posted 5 months ago #

    S2Member is definitely filtering the user query.

    add_action("pre_user_query", "c_ws_plugin__s2member_users_list::users_list_query");

    and the callback is

    /**
    				* Modifies the search query.
    				*
    				* Affects searches performed in the list of Users.
    				*
    				* @package s2Member\Users_List
    				* @since 3.5
    				*
    				* @attaches-to <code></code>add_action("pre_user_query");<code></code>
    				*
    				* @param obj $query Expects a <code>WP_User_Query</code> object, by reference.
    				* @return null After possibly modifying the <code></code>$query<code></code> object.
    				*/
    				public static function users_list_query (&$query = FALSE)
    					{
    						global $wpdb; // Need this global object reference.
    
    						foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;
    						do_action ("ws_plugin__s2member_before_users_list_search", get_defined_vars ());
    						unset /* Unset defined __refs, __v. */ ($__refs, $__v);
    
    						if (isset ($query->query_vars) && !is_network_admin ()) // NOT in Network admin panels.
    							if (is_array ($qv = $query->query_vars) && ($s = trim ($qv["search"], "* \t\n\r\x0B")) && ($s = "%" . esc_sql (like_escape ($s)) . "%"))
    								{
    									$query->query_fields = "SQL_CALC_FOUND_ROWS DISTINCT(<code>&quot; . $wpdb->users . &quot;</code>.<code>ID</code>)";
    									$query->query_from = " FROM <code>&quot; . $wpdb->users . &quot;</code>, <code>&quot; . $wpdb->usermeta . &quot;</code>"; // Include meta table also.
    									$query->query_where = " WHERE <code>&quot; . $wpdb->users . &quot;</code>.<code>ID</code> = <code>&quot; . $wpdb->usermeta . &quot;</code>.<code>user_id</code>"; // Join w/ meta table.
    									$query->query_where .= " AND (" . apply_filters ("ws_plugin__s2member_before_users_list_search_where_or_before", "", get_defined_vars ());
    									$query->query_where .= " (<code>&quot; . $wpdb->users . &quot;</code>.<code>user_login</code> LIKE '" . $s . "' OR <code>&quot; . $wpdb->users . &quot;</code>.<code>user_nicename</code> LIKE '" . $s . "' OR <code>&quot; . $wpdb->users . &quot;</code>.<code>display_name</code> LIKE '" . $s . "' OR <code>&quot; . $wpdb->users . &quot;</code>.<code>user_email</code> LIKE '" . $s . "' OR <code>&quot; . $wpdb->users . &quot;</code>.<code>user_url</code> LIKE '" . $s . "')";
    									$query->query_where .= " OR ((<code>&quot; . $wpdb->usermeta . &quot;</code>.<code>meta_key</code> = 'first_name' OR <code>&quot; . $wpdb->usermeta . &quot;</code>.<code>meta_key</code> = 'last_name') AND <code>&quot; . $wpdb->usermeta . &quot;</code>.<code>meta_value</code> LIKE '" . $s . "')";
    									$query->query_where .= " OR (<code>&quot; . $wpdb->usermeta . &quot;</code>.<code>meta_key</code> = '" . $wpdb->base_prefix . "s2member_subscr_id' AND <code>&quot; . $wpdb->usermeta . &quot;</code>.<code>meta_value</code> LIKE '" . $s . "')";
    									$query->query_where .= " OR (<code>&quot; . $wpdb->usermeta . &quot;</code>.<code>meta_key</code> = '" . $wpdb->base_prefix . "s2member_custom' AND <code>&quot; . $wpdb->usermeta . &quot;</code>.<code>meta_value</code> LIKE '" . $s . "')";
    									$query->query_where .= " OR (<code>&quot; . $wpdb->usermeta . &quot;</code>.<code>meta_key</code> = '" . $wpdb->base_prefix . "s2member_custom_fields' AND <code>&quot; . $wpdb->usermeta . &quot;</code>.<code>meta_value</code> LIKE '" . $s . "')";
    									if(apply_filters("ws_plugin__s2member_users_list_search_admin_notes", false, get_defined_vars())) // Off by default; this can get very slow on large sites.
    										$query->query_where .= " OR (<code>&quot; . $wpdb->usermeta . &quot;</code>.<code>meta_key</code> = '" . $wpdb->base_prefix . "s2member_notes' AND <code>&quot; . $wpdb->usermeta . &quot;</code>.<code>meta_value</code> LIKE '" . $s . "')";
    									$query->query_where .= apply_filters ("ws_plugin__s2member_before_users_list_search_where_or_after", "", get_defined_vars ()) . ")"; // Leaving room for additional searches here.
    
    									if(is_multisite()) // On a Multisite Network we need to make sure we're searching only users w/ capabilities on this blog.
    										$query->query_where .= " AND <code>&quot; . $wpdb->users . &quot;</code>.<code>ID</code> IN(SELECT DISTINCT(<code>user_id</code>) FROM <code>&quot; . $wpdb->usermeta . &quot;</code> WHERE <code>meta_key</code> = '" . $wpdb->prefix . "capabilities')";
    
    									$query->query_from = apply_filters ("ws_plugin__s2member_before_users_list_search_from", $query->query_from, get_defined_vars ());
    									$query->query_where = apply_filters ("ws_plugin__s2member_before_users_list_search_where", $query->query_where, get_defined_vars ());
    								}
    						foreach(array_keys(get_defined_vars())as$__v)$__refs[$__v]=&$$__v;
    						do_action ("ws_plugin__s2member_after_users_list_search", get_defined_vars ());
    						unset /* Unset defined __refs, __v. */ ($__refs, $__v);
    
    						return /* Return for uniformity. */;
    					}

    Now what exactly is happening, I couldn't say, but they are clearly modifying the query_where and query_from strings.

  7. CK MacLeod
    Member
    Posted 5 months ago #

    Very interesting, and thanks much. It probably would have taken me a day and several clumps of hair to get to that code.

    S2Member takes over a lot of "user list" functionality in admin. I guess that the way it's written, including itself in, also affects our searches taking place outside of admin for other purposes.

    I'll see if simply adding a condition (via a temporary hack) disables it in civilian areas while preserving it in admin, though, if that works, it would presumably also disable the expanded functionality that I like, and may interfere with other S2M functions. Even if it affects SUL searches only, I'm guessing a better solution will still require either re-producing pieces of the S2M code or filtering it.

    Somewhere at the bottom of this all might be a really nice implementation of a "not so simple user listing" for membership sites like the one I'm working on. The end goal would be ability to search a database of thousands of members in different ways and to tailor output, though other peculiarities of S2Member's design might make that harder than it should be, and harder to transfer to non-S2Member set-ups.

    Thanks, again. By the way in addition to using SUL, I'm also using your Nav Menu Roles plug-in - very handy and well-designed!

  8. helgatheviking
    Member
    Plugin Author

    Posted 5 months ago #

    If you use a good text editor you can search through whole folders which is very useful. I highly recommend Sublime Text 3.

    Anyway, without testing extensively, I *think* I can slightly move one of my action hooks. This would then allow you to unhook the S2M filter from the SUL shortcode and then add it back after the fact. I have a before loop and an after loop hook already, just that the before loop hook occurs after the query which is too late for this to work. Moving it up a line doesn't make any difference.

    Please go into my main plugin file, simple-user-listing.php and find the following:

    // before the user listing loop
    do_action( 'simple_user_listing_before_loop', $query_id );

    Cut it and paste it just before

    // the query itself
    $sul_users = new WP_User_Query( $args );

    Then in your theme's functions.php (or a site-specific plugin) add the following:

    function kia_protect_sul_from_s2(){
    	remove_action('pre_user_query', 'c_ws_plugin__s2member_users_list::users_list_query');
    }
    add_action( 'simple_user_listing_before_loop', 'kia_protect_sul_from_s2' );
    
    function kia_restore_s2(){
    	add_action('pre_user_query', 'c_ws_plugin__s2member_users_list::users_list_query');
    }
    add_action( 'simple_user_listing_after_loop', 'kia_restore_s2' );

    The S2 query mods should no longer apply to SUL shortcodes. Let me know if that works for you and I will commit the update.

  9. CK MacLeod
    Member
    Posted 5 months ago #

    Works fine as far as restoring expected functionality - searching names only - without disturbing other S2Member functions. However, as also expected, it does interfere with the unexpected but desirable expanded functionality of searching S2Member usermeta fields.

    Just as a further note possibly for your own purposes, if I remove the added functions, but leave the change to simple-user-listing.php, there is no observable effect: Everything is as before. So, as far as I can tell, there's no harm in moving the "do_action" to the new spot.

    This is a great start for me in terms of getting to the control I want - so big further thanks! I'm going to leave things as they were for now, except for the single change to simple-user-listing.php, but will next look into adding the S2Member meta_key ("wp_s2member_custom_fields") to the query args directly via function. Will tackle it after lunch (I'm in California and we're coming up on High Noon).

    I'll also look at Sublime Text 3 later on. Usually I search multiple files with Notepad++, but, without your assistance/confirmation I wouldn't have known for sure that what I was looking for was even there or directly relevant (thus the possible day long hair-pulling). I also wouldn't have come up with a version of your S2M protection code anytime soon or without extensive trial and error.

  10. helgatheviking
    Member
    Plugin Author

    Posted 5 months ago #

    That's good. There should be no noticeable difference in moving my hook, so I will push that out.

    I knew it would disable your unintended benefits, but you should be able to add them back by borrowing bits from S2's function. You can add another filter to pre_user_query and you can specifically target the SUL query by checking if the query has a query_id = simple_user_listing... or whatever value you pass as the query_id in the shortcode (this way you don't monkey with non-SUL user queries). I put that in there for advanced hijinx!

    Good luck. and if you liked this plugin maybe you could leave a review:
    http://wordpress.org/support/view/plugin-reviews/simple-user-listing

  11. CK MacLeod
    Member
    Posted 5 months ago #

    Review done! Sorry it took me so long to get around to it.

    Bad news, but I have not yet begun to fight, is that my first two tries at getting it to search the S2 meta_key "properly" failed.

    In addition to the S2protect functions, I tried to follow the FAQ "billing_city" example, but substituting S2M's "wp_s2member_custom_fields" for "billing_city" in both the search-author.php and the meta_search functions (below).

    The other difference, and potential area for further research, first going back to S2M's code as above, is that "wp_s2member_custom_fields" is a serialized array, meaning that the search term has to be found within the array's content. I tried 'IN' instead of '=' for the meta_compare value. So, the following does NOT work, either for reasons having to do with meta_key searches that I don't understand, or because I made some error with the code that I missed. Could also be that I don't properly understand "whitelisting" of variables.

    function kia_meta_search( $args ){
      // this $_GET is the name field of the custom input in search-author.php, using wp_s2member_custom_fields meta_key
        $search = ( isset($_GET['wp_s2member_custom_fields'])) ? sanitize_text_field($_GET['wp_s2member_custom_fields']) : false ;
        if ( $search ){
    		$args['meta_key'] = 'wp_s2member_custom_fields';
    		$args['meta_value'] = $search;
            //tried "in" since the meta_key contains a serialized array with a lot of info
    		$args['meta_compare'] = 'IN';
        }
        return $args;
    }
    add_filter('sul_user_query_args', 'kia_meta_search');
    
    //whitelisting the S2Member variable
    
    function kia_search_vars( $vars ){
        $vars[] = 'wp_s2member_custom_fields';
        return $vars;
    }
    add_filter('sul_user_allowed_search_vars', 'kia_search_vars');
  12. CK MacLeod
    Member
    Posted 5 months ago #

    note: The S2Member developers are themselves aware that using a serialized array for their custom user fields was a questionable decision, and they have periodically promised to re-do or look seriously into re-doing their own code. Initial research on searching serialized arrays in databases indicates widespread reluctance to deal with them at all. On the other hand, we know from the "unintended benefit" that the array is indeed somewhat readily searchable, at least on this relatively small scale. At least the S2M people figured it out.

    Anyway, I won't take it amiss if you choose to bail out on this side-project if this turns out to be the problem, and you don't see some other obvious mistake in my approach, but, if and when I manage to solve it, I'll let you know.

  13. helgatheviking
    Member
    Plugin Author

    Posted 5 months ago #

    Keep in mind that my billing_zip example includes changing the input name of the search box... which is important b/c later you are doing

    $search = ( isset($_GET['wp_s2member_custom_fields'])) ? sanitize_text_field($_GET['wp_s2member_custom_fields']) : false ;
        if ( $search ){

    If you aren't changing the search, then you need to make sure the $_GET has the right name (which is 'as' by default). So that code would be:

    $search = ( isset($_GET['as'])) ? sanitize_text_field($_GET['as']) : false ;
        if ( $search ){

    The "white-listing" is more important for people who want 2 search inputs.

    However, all that said, I would focus less on my code and more on trying to re-implement the special query_where and query_from code S2 has implemented in their plugin. That seems more the ticket to restoring their "unintended" consequences.

Reply

You must log in to post.

About this Plugin

About this Topic

Tags

No tags yet.