wake-up-neo.net

benutzerprofile in die Suchergebnisse aufnehmen?

Ich muss Benutzerprofile zusammen mit Beiträgen und Seiten in die Front-End-Suche einbeziehen.

Ich habe nach Lösungen für dieses Problem gesucht (sowohl hier bei WSE als auch an anderer Stelle im Web) und muss keine Hilfe finden. Die nächstgelegenen, die ich gefunden habe, sind Autorenprofil in Suchergebnissen einschließen und WordPress-Suche erweitern auf Benutzer-Suche einschließen , von denen keine vernünftige Antworten haben.

Um die Anforderung klarer zu formulieren: Die Site hat Beiträge, Seiten und (natürlich) Benutzer. Wenn einEndbenutzereine Suche imFront-Enddurchführt, muss das Suchergebnis Beiträge enthalten und Seiten, deren Titel oder post_content die Suchbegriffe enthält (wie es bei Front-End-Suchen üblich ist)plusdie Profile von Benutzern, die mit übereinstimmen ) die Suchbegriffe (siehe unten, was unter einem Benutzer zu verstehen ist , der den Suchbegriffen entspricht ).

Der wichtige Punkt ist, dass ichnichtüber die Suche nach Beiträgen spreche, die von einem bestimmten Benutzer verfasst wurden!

Begründung der Anforderung

Umzu verstehen, warumich diese Anforderung habe, ist es möglicherweise hilfreich zu wissen, dass ein Teil der Site alle Benutzerprofile und einEnde auflistet -userkann auf den Namen eines beliebigen Benutzers klicken, um dessen Profil anzuzeigen. Im Benutzerprofil werden verschiedene usermeta angezeigt. Aus der PerspektiveEndbenutzergibt es keinen Unterschied zwischen den Benutzerprofilen und Posts/Seiten, die sie im Front-End erreichen können.

Angenommen, das Benutzerprofil für einen bestimmten Benutzer zeigt die Zeichenfolge "foo" an (d. H. Eine der angezeigten usermetas für diesen Benutzer enthält "foo"). Wenn einEndbenutzernach "foo" sucht, wird erwartet, dass das Profil dieses Benutzers in den Suchergebnissen angezeigt wird.

Provisorische Lösung

Das Folgende ist die Lösung, die ich mir ausgedacht habe. Diese Lösung funktioniert, aber ich glaube, es muss einen besseren/einfacheren/weniger spröden Weg geben, um dies zu erreichen:

  1. einen nicht öffentlichen benutzerdefinierten Beitragstyp registrieren (z. B. "Mein_Benutzer_Profil")
  2. hängen Sie sich in user_register ein. Fügen Sie einen Beitrag vom Typ 'mein_Benutzerprofil' ein und fügen Sie ein postmeta hinzu (sagen Sie 'meine_Benutzer_ID'), dessen Wert die ID des neu registrierten Benutzers ist
  3. hängen Sie sich in the_posts ein. Wenn is_search() true ist, führen Sie eine get_users() aus, die verschiedene usermeta nach den Suchbegriffen inend-userssearch durchsucht. Führen Sie dann eine get_posts() für Posts des Typs 'my_user_profile' mit postmeta 'my_user_id' "IN" der in der get_users() gefundenen Benutzer-ID aus. und dann die Zusammenführung der von der ursprünglichen Suche gefundenen Posts mit den von myget_posts() gefundenen Posts des Typs 'my_user_profile' zurückgeben.
  4. hängen Sie sich in post_type_link ein (der von get_permalink() aufgerufen wird). Wenn der $post->post_type 'mein_benutzer_profil' ist, geben Sie get_author_posts_url() für den Benutzer zurück, dessen ID in der 'meine_benutzer_id' postmeta von $post enthalten ist. Auf diese Weise muss der search.php des Themas keinen Code mit spezifischen Kenntnissen darüber enthalten, wie die obigen Schritte die Suchergebnisse "erweitert" haben
  5. hängen Sie sich in get_the_excerpt ein. Wenn $post->post_type 'mein_benutzer_profil' ist, geben Sie den Wert eines bestimmten usermeta (sagen Sie 'mein_auszug') für den Benutzer zurück, dessen ID in der 'meine_benutzer_id' postmeta von $post enthalten ist. Auf diese Weise muss der search.php des Themas keinen Code mit spezifischen Kenntnissen darüber enthalten, wie die obigen Schritte die Suchergebnisse "erweitert" haben

Code für vorläufige Lösung

[Anmerkung: Code für Schritt 3 wurde bearbeitet, um einen Fehler zu beheben, den ich beim Transkribieren (und Desinfizieren) meines Arbeitscodes eingeführt habe]

Hier ist der Code für meine vorläufige Lösung:

// step #1
add_action( 'init', 'wpse_register_post_type' );
function wpse_register_post_type() {
    $args = array(
        'public' => false,
        'show_ui' => false,
        'supports' => array(
            'title',
            'author',
        ),
    );
    register_post_type( 'my_user_profile', $args );
}

// step #2
add_action( 'user_register', 'wpse_add_user_profile_post' );
function wpse_add_user_profile_post( $my_user_id ) {
    $user = get_user_by( 'ID', $my_user_id );
    $args = array(
        'post_type' => 'my_user_profile',
        // so that I can find them easier when manually looking thru the wp_posts table
        'post_title' => $user->display_name,
        'post_status' => 'publish',
    );
    $post_id = wp_insert_post( $args );

    if ( ! is_wp_error( $post_id ) ) {
        update_post_meta( $post_id, 'my_user_id', $my_user_id );
    }

    return;
}

// step #3
add_filter( 'the_posts', array( $this, 'wpse_user_search' ), 10, 2 );
function wpse_user_search( $posts, $query ) {
    if ( ! is_search() ) {
        return $posts;
    }

    $search_terms = explode( ' ', $query->get( 's' ) );
    $user_meta_keys = array( /* my usermeta keys */ );

    $args = array(
        'fields' => 'ID',
        'meta_query' => array( 'relation' => 'OR' ),
    );
    // build the meta_query
    foreach ( $user_meta_keys as $meta_key ) {
        foreach ( $search_terms as $search_term ) {
            $args['meta_query'][] = array(
                'key' => $meta_key,
                'value' => $search_term,
                'compare' => 'LIKE',
            );
        }
    }
    $users = get_users( $args );

    // get the my_user_profile posts associated with $users
    $args = array(
        'post_type' => 'my_user_profile',
        'meta_query' => array(
            array(
                'key' => 'my_user_id',
                'value' => $users,
                'compare' => 'IN',
            ),
        )
    );

    // make sure we don't call ourselves in the get_posts() below
    remove_filter( 'the_posts', array( $this, 'user_search' ) );

    $user_posts = get_posts( $args );

    add_filter( 'the_posts', array( $this, 'user_search' ), 10, 2 );

    $posts = array_merge( $posts, $user_posts );

    return $posts;
}

// step 4
add_filter( 'post_type_link', array( $this, 'wpse_user_profile_permalink' ), 10, 2 );
function wpse_user_profile_permalink( $post_link, $post ) {
    if ( 'my_user_profile' !== $post->post_type ) {
        return $post_link;
    }

    // rely on WP_Post::__get() magic method to get the postmeta
    return get_author_posts_url( $post->my_user_id );
}

// step 5
add_filter( 'get_the_excerpt', array( $this, 'wpse_user_profile_excerpt' ), 10, 2 );
function wpse_user_profile_excerpt( $excerpt, $post ) {
    if ( 'my_user_profile' !== $post->post_type ) {
        return $excerpt;
    }

    // rely on WP_Post::__get() magic method to get the postmeta
    $user = get_user_by( 'ID', $post->my_user_id );

    // rely on WP_User::__get() magic method to get the usermeta
    return $user->my_excerpt;
}

Wie ich bereits sagte, funktioniert das oben Genannte, aber ich kann nicht anders, als zu glauben, dass es einen einfacheren Weg gibt, an den ich einfach nicht gedacht habe.

Alternative (abgelehnte) Lösung

Eine Alternative, die ich mir überlegt, aber abgelehnt habe, weil sie komplexer/spröder erscheint als die oben genannte Lösung, ist:

  1. wie oben Nr. 1
  2. wie oben Nr. 2
  3. hängen Sie sich in personal_options_update ein. Fügen Sie sie für jedes usermeta, das ich bereits für einen Benutzer speichere, als postmeta zum Beitrag des Typs 'my_user_profile' hinzu, der dem angegebenen Benutzer zugeordnet ist
  4. hängen Sie posts_join und posts_where ein, um die verschiedenen in Schritt 3 hinzugefügten postmeta zu durchsuchen
  5. wie oben Nr. 4
  6. wie oben Nr. 5

Hat jemand eine einfachere/weniger spröde Lösung?

Ich habe keine gebrauchsfertige Lösung. Ich denke jedoch, dass Sie die Abfrage verbessern sollten, damit Sie das Feld der Benutzer darin haben. Ich denke, das folgende Beispiel zeigt es mehr.

Die beiden Filter-Hooks sind notwendig und ergeben für die Abfrage folgendes Ergebnis:

SELECT SQL_CALC_FOUND_ROWS wpbeta_posts.ID
FROM wpbeta_posts JOIN wpbeta_users
WHERE 1=1 
AND (((wpbeta_posts.post_title LIKE '%search_string%')
OR (wpbeta_posts.post_excerpt LIKE '%search_string%')
OR (wpbeta_posts.post_content LIKE '%search_string%'))) 
AND wpbeta_posts.post_type IN ('post', 'page', 'attachment')
AND (wpbeta_posts.post_status = 'publish'
OR wpbeta_posts.post_status = 'private')
OR (wpbeta_users.display_name LIKE '%search_string%') 
ORDER BY wpbeta_posts.post_title LIKE '%search_string%' DESC, wpbeta_posts.post_date DESC
LIMIT 0, 10

Sie können diese Abfrage auch in Ihren Tests ganz einfach über ein Plug-in wie Debug Objects oder Query Monitor lesen. Die SQL-Abfrage ist nur ein Beispiel und sicher nicht das Ergebnis, um es zu verwenden. Sie müssen mit ihnen spielen und die Haken unten einbeziehen, um das richtige Ergebnis zu erzielen. Die Quelle bekommt auch nur ein Beispiel, um ein Feld aus der Benutzertabelle hinzuzufügen, den display_name. Vielleicht kann ein SQL "Nerd" helfen.

// Enhance the JOIN clause of the WP Query with table users.
add_filter( 'posts_join', function( $join, $wp_query ) {

    // No search string, exit.
    if ( empty( $wp_query->query_vars['s'] ) ) {
        return $join;
    }

    global $wpdb;
    $join .= ' JOIN ' . $wpdb->users;

    return $join;
}, 10, 2 );

// Enhance WHERE clause of the WP Query with user display name. 
add_filter( 'posts_where', function( $where, $wp_query ) {

    // No search, exit.
    if ( ! is_search() ) {
        return $where ;
    }

    global $wpdb;
    $where .= ' OR (' . $wpdb->users . '.display_name LIKE \'%' . esc_sql( $wp_query->query_vars['s'] ) . '%\')';

    return $where ;
}, 10, 2 );
1
bueltge