So durchsuchen Sie alle Benutzer-Metas aus users.php im Admin

14

Das Suchformular oben in der Benutzerliste im Admin-Bereich (wp-admin / users.php) ist eingeschränkt und durchsucht nicht alle Benutzer-Metafelder, wie z. B. Bio, Instant Messenger-Handles usw., habe ich nicht konnte ein Plugin finden, das dies hinzufügen kann.

Ist jemandem ein Plugin oder eine Funktion bekannt, die ich erstellen könnte, um die Suche nach dem gesamten Datum in der _usermeta-DB zu erweitern - idealerweise sogar zusätzliche Felder, die von einem Plugin oder einer Funktion erstellt wurden.

John Chandler
quelle

Antworten:

24

Hi @ user2041:

Wie Sie wissen, müssen Sie die durchgeführte Suche ändern, indem Sie die Werte in der Instanz der WP_User_Searchfür die Suche verwendeten Klasse ändern (Sie finden den Quellcode unter, /wp-admin/includes/user.phpwenn Sie ihn untersuchen möchten.)

Das WP_User_SearchObjekt

So print_r()sieht ein Objekt in WordPress 3.0.3 aus, wenn Sie nach dem Begriff " TEST" suchen und ohne andere Plugins, die sich darauf auswirken könnten:

WP_User_Search Object
(
  [results] => 
  [search_term] => TEST
  [page] => 1
  [role] => 
  [raw_page] => 
  [users_per_page] => 50
  [first_user] => 0
  [last_user] => 
  [query_limit] =>  LIMIT 0, 50
  [query_orderby] =>  ORDER BY user_login
  [query_from] =>  FROM wp_users
  [query_where] =>  WHERE 1=1 AND (user_login LIKE '%TEST%' OR user_nicename LIKE '%TEST%' OR user_email LIKE '%TEST%' OR user_url LIKE '%TEST%' OR display_name LIKE '%TEST%')
  [total_users_for_query] => 0
  [too_many_total_users] => 
  [search_errors] => 
  [paging_text] => 
)

Der pre_user_searchHaken

Um die Werte des WP_User_SearchObjekts zu ändern, verwenden Sie den 'pre_user_search'Hook, der die aktuelle Instanz des Objekts empfängt. Ich habe print_r()von diesem Hook aus angerufen , um auf die Werte zuzugreifen, die ich oben angezeigt habe.

Das folgende Beispiel, das Sie in die functions.phpDatei Ihres Themas kopieren oder in einer PHP-Datei für ein Plugin verwenden können, das Sie schreiben, bietet die Möglichkeit, die Beschreibung des Benutzers zu durchsuchen und in den anderen Feldern zu suchen. Die Funktion ändert die query_fromund die query_whereEigenschaften des $user_searchObjekts, die Sie benötigen, um mit SQL vertraut zu sein.

Sorgfältiges Ändern von SQL in Hooks

Der Code in der yoursite_pre_user_search()Funktion setzt voraus, dass kein anderes Plugin die query_wherevorhergehende Klausel geändert hat . Wenn ein anderes Plugin die where-Klausel so geändert hat, dass das Ersetzen 'WHERE 1=1 AND ('durch "WHERE 1=1 AND ({$description_where} OR"nicht mehr funktioniert, bricht dies ebenfalls. Es ist viel schwieriger, eine robuste Erweiterung zu schreiben, die von keinem anderen Plug-In beschädigt werden kann, wenn Sie SQL wie dieses ändern, aber es ist, was es ist.

Fügen Sie beim Einfügen von SQL in Hooks führende und nachfolgende Leerzeichen hinzu

Beachten Sie auch, dass es bei der Verwendung von SQL wie " INNER JOIN {$wpdb->usermeta} ON "folgt in WordPress immer eine gute Idee ist, führende und nachfolgende Leerzeichen "INNER"einzufügen " FROM wp_postsINNER JOIN {$wpdb->usermeta} ON ".

Verwenden Sie "{$wpdb->table_name"}anstelle von Hardcoding-Tabellennamen

Verwenden Sie als Nächstes immer die $wpdbEigenschaften, um auf Tabellennamen zu verweisen, falls die Site das Tabellenpräfix von 'wp_'in etwas anderes geändert hat . Daher ist es besser, auf "{$wpdb->users}.ID" (mit doppelten Anführungszeichen, nicht mit einfachen Anführungszeichen) zu verweisen, anstatt hart zu codieren "wp_users.ID".

Beschränken Sie die Abfrage auf "Nur wenn Suchbegriffe vorhanden"

Zuletzt müssen Sie die Abfrage nur ändern, wenn es einen Suchbegriff gibt, den Sie testen können, indem Sie die search_termEigenschaft des WP_User_SearchObjekts überprüfen .

Die yoursite_pre_user_search()Funktion für'pre_user_search'

add_action('pre_user_search','yoursite_pre_user_search');
function yoursite_pre_user_search($user_search) {
  global $wpdb;
  if (!is_null($user_search->search_term)) {
    $user_search->query_from .= " INNER JOIN {$wpdb->usermeta} ON " . 
      "{$wpdb->users}.ID={$wpdb->usermeta}.user_id AND " .
      "{$wpdb->usermeta}.meta_key='description' ";
    $description_where = $wpdb->prepare("{$wpdb->usermeta}.meta_value LIKE '%s'",
      "%{$user_search->search_term}%");
    $user_search->query_where = str_replace('WHERE 1=1 AND (',
      "WHERE 1=1 AND ({$description_where} OR ",$user_search->query_where);    
  }
}

Die Suche nach jedem Metaschlüssel-Wert-Paar erfordert eine SQL JOIN

Natürlich ist der wahrscheinliche Grund, warum WordPress Sie nicht in Usermeta-Feldern suchen lässt, dass jedes der Felder eine SQL-Anweisung hinzufügt JOINund eine Abfrage mit zu vielen Verknüpfungen in der Tat langsam sein kann. Wenn Sie wirklich in vielen Feldern suchen müssen, würde ich '_search_cache'in usermeta ein Feld erstellen, das alle anderen Informationen in einem usermeta-Feld sammelt, sodass nur ein Join erforderlich ist, um alle zu durchsuchen.

Führende Unterstriche in Metatasten weisen WordPress an, nicht anzuzeigen

Beachten Sie, dass der führende Unterstrich in '_search_cache'WordPress angibt, dass dies ein interner Wert ist und dem Benutzer niemals etwas anzuzeigen ist.

Erstellen Sie einen Suchcache mit den 'profile_update'und 'user_register'Hooks

Sie müssen also beides einhaken, 'profile_update'und 'user_register'das wird ausgelöst, wenn Sie einen Benutzer speichern bzw. einen neuen Benutzer registrieren. Sie können alle Metaschlüssel und ihre Werte in diesen Hooks erfassen (aber diejenigen mit Werten, die serialisiert oder URL-codiert sind, weglassen) und sie dann verketten, um sie mit dem '_search_cache'Schlüssel als einen langen Metawert zu speichern .

Speichern Sie Meta als begrenzte '|'Schlüsselwertpaare

Ich habe beschlossen, alle Schlüsselnamen und alle ihre Werte zu erfassen und zu einer großen Zeichenfolge mit Doppelpunkten (":") zu verknüpfen, die die Schlüssel von den Werten trennen, und vertikale Balken ("|"), die die Schlüssel-Wert-Paare wie folgt trennen (I habe sie über mehrere Zeilen umbrochen, damit du sie ohne Scrollen nach rechts einfügen kannst):

nickname:mikeschinkel|first_name:mikeschinkel|description:This is my bio|
rich_editing:true|comment_shortcuts:false|admin_color:fresh|use_ssl:null|
wp_user_level:10|last_activity:2010-07-28 01:25:46|screen_layout_dashboard:2|
plugins_last_view:recent|screen_layout_post:2|screen_layout_page:2|
business_name:NewClarity LLC|business_description:WordPress Plugin Consulting|
phone:null|last_name:null|aim:null|yim:null|jabber:null|
people_lists_linkedin_url:null

Aktiviert die spezialisierte Suche nach Meta mithilfe von key:value

Durch Hinzufügen des Schlüssels und der Werte, wie wir es getan haben, können Sie Suchen wie " rich_editing:true" durchführen, um alle Personen mit umfangreichen Bearbeitungsmöglichkeiten zu finden, oder nach " phone:null" suchen, um diejenigen ohne Telefonnummer zu finden.

Aber Vorsicht vor Suchartefakten

Natürlich erzeugt diese Technik möglicherweise unerwünschte Suchartefakte wie die Suche nach "Unternehmen", und alle werden aufgelistet. Wenn dies ein Problem ist, möchten Sie möglicherweise keinen so aufwändigen Cache verwenden.

Die yoursite_profile_update()Funktion für 'profile_update'und'user_register'

Die Funktion yoursite_profile_update()kann wie yoursite_pre_user_search()oben beschrieben in die functions.phpDatei Ihres Themas kopiert oder in einer PHP-Datei für ein Plugin verwendet werden, das Sie schreiben:

add_action('profile_update','yoursite_profile_update');
add_action('user_register','yoursite_profile_update');
function yoursite_profile_update($user_id) {
  $metavalues = get_user_metavalues(array($user_id));
  $skip_keys = array(
    'wp_user-settings-time',
    'nav_menu_recently_edited',
    'wp_dashboard_quick_press_last_post_id',
  );
  foreach($metavalues[$user_id] as $index => $meta) {
    if (preg_match('#^a:[0-9]+:{.*}$#ms',$meta->meta_value))
      unset($metavalues[$index]); // Remove any serialized arrays
    else if (preg_match_all('#[^=]+=[^&]\&#',"{$meta->meta_value}&",$m)>0)
      unset($metavalues[$index]); // Remove any URL encoded arrays
    else if (in_array($meta->meta_key,$skip_keys))
      unset($metavalues[$index]); // Skip and uninteresting keys
    else if (empty($meta->meta_value)) // Allow searching for empty
      $metavalues[$index] = "{$meta->meta_key }:null";
    else if ($meta->meta_key!='_search_cache') // Allow searching for everything else
      $metavalues[$index] = "{$meta->meta_key }:{$meta->meta_value}";
  }
  $search_cache = implode('|',$metavalues);
  update_user_meta($user_id,'_search_cache',$search_cache);
}

Aktualisierte yoursite_pre_user_search()Funktion, die ein einzelnes SQL JOINfür die Suche nach allen interessanten Metawerten ermöglicht

Um yoursite_profile_update()einen Effekt zu erzielen, müssen Sie natürlich Änderungen vornehmen yoursite_pre_user_search(), um den '_search_cache'Metaschlüssel anstelle der Beschreibung zu verwenden, die wir hier haben (mit den gleichen Einschränkungen wie oben erwähnt):

add_action('pre_user_search','yoursite_pre_user_search');
function yoursite_pre_user_search($user_search) {
  global $wpdb;
  if (!is_null($user_search->search_term)) {
    $user_search->query_from .= " INNER JOIN {$wpdb->usermeta} ON " . 
      "{$wpdb->users}.ID={$wpdb->usermeta}.user_id AND " . 
      "{$wpdb->usermeta}.meta_key='_search_cache' ";
    $meta_where = $wpdb->prepare("{$wpdb->usermeta}.meta_value LIKE '%s'",
      "%{$user_search->search_term}%");
    $user_search->query_where = str_replace('WHERE 1=1 AND (',
      "WHERE 1=1 AND ({$meta_where} OR ",$user_search->query_where);
  }
}
MikeSchinkel
quelle
@MikeSchinkel Tolle, gründliche Antwort! Dies ist eines der vielen Male auf dieser Website, bei denen ich mir wünschte, ich könnte für eine so gut recherchierte Antwort auf eine Frage, die nicht auf Lager ist, mehrere Stimmen vergeben.
MathSmath
Danke @MathSmath - Zu lernen, dass die Leute es zu schätzen wissen, ist das, was mich am Laufen hält. :)
MikeSchinkel
Mike, danke für die gründliche Antwort! Ich werde dies später in mein Thema einarbeiten und sehen, wer es ist.
John Chandler
Mike, wir sind nah dran, aber ..! Klar, das bringt mich vom richtigen Start weg. Wenn Sie entweder die zuerst erwähnte einzelne Funktion oder die beiden Funktionen zur Verwendung von profile_update verwenden, können Sie suchen und die richtigen Ergebnisse erzielen. Leider stören diese Funktionen die Auflistung, als ich die Datei users.php zum ersten Mal aufrufe (für die kein Suchbegriff angegeben wurde). Es werden nicht alle Benutzer angezeigt. Wenn ich auf den Filter Alle klicke, werden nur zwei (von vier) angezeigt, von denen einer ich bin. Wenn ich auf den Filter Administratoren klicke, werden keine Benutzer angezeigt - nicht einmal ich! Irgendwelche Ideen?
John Chandler
Ein bisschen mehr Infos. Ich habe die erste Funktion bearbeitet, um ein Feld mit dem Namen "Firma" zu durchsuchen, das ich über das Plugin für zusätzliche Benutzerdetails hinzugefügt habe. Es funktioniert, wenn ich nach einem Benutzer mit einem Firmennamen suche. Es scheint jedoch, dass das Sortieren nach "Alle" ohne Suche nur die beiden Ergebnisse zurückgibt, die Daten im Feld "Firma" enthalten, und nicht die Benutzer, die keine Daten im Feld "Firma" enthalten.
John Chandler
4

Ich habe MikeSchinkels Herangehensweise und die gründliche Erklärung oben sehr geschätzt. Das war super hilfreich. Ich konnte es nicht zum Laufen bringen, da pre_user_search veraltet ist und in 3.2 nicht mehr funktioniert. Ich habe versucht, es einfach mit pre_user_query auszuschalten, aber das hat auch nicht funktioniert. Die Sache ist, es scheint, dass $ user_search-> search_term nicht mehr funktioniert, also habe ich nur $ _GET ['s'] verwendet. Ich habe ein bisschen gehackt und konnte das in 3.2 zum Laufen bringen. Das einzige, was Sie festlegen müssen, ist Ihr Array durchsuchbarer Metadaten.

//Searching Meta Data in Admin
add_action('pre_user_query','yoursite_pre_user_search');
function yoursite_pre_user_search($user_search) {
    global $wpdb;
    if (!isset($_GET['s'])) return;

    //Enter Your Meta Fields To Query
    $search_array = array("customer_id", "postal_code", "churchorganization_name", "first_name", "last_name");

    $user_search->query_from .= " INNER JOIN {$wpdb->usermeta} ON {$wpdb->users}.ID={$wpdb->usermeta}.user_id AND (";
    for($i=0;$i<count($search_array);$i++) {
        if ($i > 0) $user_search->query_from .= " OR ";
            $user_search->query_from .= "{$wpdb->usermeta}.meta_key='" . $search_array[$i] . "'";
        }
    $user_search->query_from .= ")";        
    $custom_where = $wpdb->prepare("{$wpdb->usermeta}.meta_value LIKE '%s'", "%" . $_GET['s'] . "%");
    $user_search->query_where = str_replace('WHERE 1=1 AND (', "WHERE 1=1 AND ({$custom_where} OR ",$user_search->query_where);    
}

Hoffe das hilft jemandem.

David
quelle
Hat jemand kürzlich Erfahrungen damit gemacht? Persönlich kann ich keines dieser Codes zum Laufen bringen, auch nicht die neuesten. Ich habe einige andere Optionen ausprobiert, aber Probleme mit der Ergebnisseitendarstellung festgestellt .
Robert Andrews
1

Hier ist eine Lösung für die neueste Version von WordPress.

add_action( 'pre_user_query', 'yoursite_pre_user_search'  );
    function yoursite_pre_user_search( $query ) {
        $query->query_where .= "YOUR QUERY '" . str_replace("*", "%", $query->query_vars[ 'search' ] ) . "')";
    }
Patrik Grinsvall
quelle
-1

Das habe ich mir für WordPress 4.7.1 ausgedacht, das die Platzhaltersuche zu allen Benutzer-Metadaten hinzufügt.


add_action( 'pre_user_query', 'ds_pre_user_search'  );
function ds_pre_user_search( $query ) {
    global $wpdb;

    if( empty($_REQUEST['s']) ){return;}
    $query->query_from .= ' LEFT JOIN '.$wpdb->usermeta.' ON '.$wpdb->usermeta.'.user_id = '.$wpdb->users.'.ID';
    $query->query_where = "WHERE 1=1 AND (user_login LIKE '%".$_REQUEST['s']."%' OR ID = '".$_REQUEST['s']."' OR meta_value LIKE '%".$_REQUEST['s']."%')";
    return $query;
}

Grundsätzlich verknüpfen wir nur die Tabellen users und user_meta mit der Benutzer-ID und erstellen die WHERE-Klausel neu, um die Suche in der Spalte meta_value einzuschließen.

Wagontrader
quelle
1
Was Sie hier vorschlagen, ist höchst gefährlich ! Sie sollten niemals irgendetwas , was von einem Benutzer bereitgestellt wird, an die DB übergeben. Sie könnten Ihre Tabellen löschen, Ihre Datenbank hijacken - SQL-Injection als Suchbegriff ansehen - oder einfach alle Ihre Daten verschlüsseln. Mach "%".like_escape( $_GET['s'] )."%"stattdessen ein. Gleiches gilt für alle anderen vom Benutzer angegebenen Daten . Andernfalls wird Ihr Suchfeld zu einem offenen Tor zu Ihren Daten.
Kaiser